Updated on 2026-08-14
This commit is contained in:
parent
422afbc17f
commit
5384cf75ad
12 changed files with 961 additions and 0 deletions
|
|
@ -0,0 +1,62 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.analytics.utils
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
@ViewModelScoped
|
||||
internal class TokenListAnalyticsSender @Inject constructor(
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) {
|
||||
|
||||
fun send(maybeTokenList: Either<TokenListError, TokenList>) {
|
||||
val tokenList = (maybeTokenList as? Either.Right)?.value ?: return
|
||||
|
||||
createCardBalanceState(tokenList)?.let {
|
||||
analyticsEventHandler.send(event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded(balance = it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCardBalanceState(tokenList: TokenList): AnalyticsParam.CardBalanceState? {
|
||||
return when (val fiatBalance = tokenList.totalFiatBalance) {
|
||||
is TokenList.FiatBalance.Failed -> fiatBalance.toCardBalanceState(tokenList)
|
||||
is TokenList.FiatBalance.Loaded -> fiatBalance.toCardBalanceState()
|
||||
TokenList.FiatBalance.Loading -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun TokenList.FiatBalance.Failed.toCardBalanceState(tokenList: TokenList): AnalyticsParam.CardBalanceState {
|
||||
val currenciesStatuses = when (tokenList) {
|
||||
is TokenList.Empty -> emptyList()
|
||||
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
|
||||
is TokenList.Ungrouped -> tokenList.currencies
|
||||
}
|
||||
|
||||
return when {
|
||||
currenciesStatuses.isEmpty() -> AnalyticsParam.CardBalanceState.Empty
|
||||
currenciesStatuses.any { it.value is CryptoCurrencyStatus.NoQuote } -> {
|
||||
AnalyticsParam.CardBalanceState.NoRate
|
||||
}
|
||||
else -> AnalyticsParam.CardBalanceState.BlockchainError
|
||||
}
|
||||
}
|
||||
|
||||
private fun TokenList.FiatBalance.Loaded.toCardBalanceState(): AnalyticsParam.CardBalanceState? {
|
||||
return if (amount > BigDecimal.ZERO) {
|
||||
AnalyticsParam.CardBalanceState.Full
|
||||
} else if (amount.isZero()) {
|
||||
AnalyticsParam.CardBalanceState.Empty
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ViewModelScoped
|
||||
internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
) {
|
||||
|
||||
private var readyForRateAppNotification = false
|
||||
|
||||
fun create(clickIntents: WalletClickIntentsV2): Flow<ImmutableList<WalletNotification>> {
|
||||
val userWallet = getSelectedWalletSyncUseCase().fold(
|
||||
ifLeft = {
|
||||
Timber.e("Failed to get selected wallet $it")
|
||||
return flowOf(value = persistentListOf())
|
||||
},
|
||||
ifRight = { it },
|
||||
)
|
||||
|
||||
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
|
||||
|
||||
return combine(
|
||||
flow = getTokenListUseCase(userWallet.walletId).conflate(),
|
||||
flow2 = isReadyToShowRateAppUseCase().conflate(),
|
||||
flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(),
|
||||
// flow4 = getMissedAddressCryptoCurrenciesUseCase(userWallet.walletId).conflate(),
|
||||
) { maybeTokenList, isReadyToShowRating, isNeedToBackup ->
|
||||
// maybeTokenList.onRight { Timber.e(it.toString()) }
|
||||
// maybeMissedAddressCurrencies.onRight { Timber.e(it.toString()) }
|
||||
readyForRateAppNotification = true
|
||||
buildList {
|
||||
addCriticalNotifications(cardTypesResolver)
|
||||
|
||||
addInformationalNotifications(cardTypesResolver, maybeTokenList, clickIntents)
|
||||
|
||||
addWarningNotifications(cardTypesResolver, maybeTokenList, isNeedToBackup, clickIntents)
|
||||
|
||||
addRateTheAppNotification(isReadyToShowRating, clickIntents)
|
||||
}.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addCriticalNotifications(cardTypesResolver: CardTypesResolver) {
|
||||
addIf(
|
||||
element = WalletNotification.Critical.DevCard,
|
||||
condition = !cardTypesResolver.isReleaseFirmwareType(),
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Critical.FailedCardValidation,
|
||||
condition = cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.isAttestationFailed(),
|
||||
)
|
||||
|
||||
cardTypesResolver.getRemainingSignatures()?.let { remainingSignatures ->
|
||||
addIf(
|
||||
element = WalletNotification.Warning.LowSignatures(count = remainingSignatures),
|
||||
condition = remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addInformationalNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
maybeTokenList: Either<TokenListError, TokenList>,
|
||||
clickIntents: WalletClickIntentsV2,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.Informational.DemoCard,
|
||||
condition = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()),
|
||||
)
|
||||
|
||||
addMissingAddressesNotification(maybeTokenList, clickIntents)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addMissingAddressesNotification(
|
||||
maybeTokenList: Either<TokenListError, TokenList>,
|
||||
clickIntents: WalletClickIntentsV2,
|
||||
) {
|
||||
val currencies = maybeTokenList.getMissingAddressCurrencies()
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Informational.MissingAddresses(
|
||||
missingAddressesCount = currencies.count(),
|
||||
onGenerateClick = {
|
||||
clickIntents.onGenerateMissedAddressesClick(missedAddressCurrencies = currencies)
|
||||
},
|
||||
),
|
||||
condition = currencies.isNotEmpty(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun Either<TokenListError, TokenList>.getMissingAddressCurrencies(): List<CryptoCurrency> {
|
||||
return fold(
|
||||
ifLeft = { emptyList() },
|
||||
ifRight = { tokenList ->
|
||||
val currencies = when (tokenList) {
|
||||
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
|
||||
is TokenList.Ungrouped -> tokenList.currencies
|
||||
is TokenList.Empty -> emptyList()
|
||||
}
|
||||
|
||||
currencies
|
||||
.filter { it.value is CryptoCurrencyStatus.MissedDerivation }
|
||||
.map(CryptoCurrencyStatus::currency)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addWarningNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
tokenList: Either<TokenListError, TokenList>,
|
||||
isNeedToBackup: Boolean,
|
||||
clickIntents: WalletClickIntentsV2,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.Warning.MissingBackup(
|
||||
onStartBackupClick = clickIntents::onAddBackupCardClick,
|
||||
),
|
||||
condition = isNeedToBackup,
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Warning.TestNetCard,
|
||||
condition = cardTypesResolver.isTestCard(),
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Warning.SomeNetworksUnreachable,
|
||||
condition = tokenList.hasUnreachableNetworks(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun Either<TokenListError, TokenList>.hasUnreachableNetworks(): Boolean {
|
||||
return fold(
|
||||
ifLeft = { false },
|
||||
ifRight = { tokenList ->
|
||||
val currencies = when (tokenList) {
|
||||
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
|
||||
is TokenList.Ungrouped -> tokenList.currencies
|
||||
is TokenList.Empty -> emptyList()
|
||||
}
|
||||
|
||||
currencies.any { it.value is CryptoCurrencyStatus.Unreachable }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addRateTheAppNotification(
|
||||
isReadyToShowRating: Boolean,
|
||||
clickIntents: WalletClickIntentsV2,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.RateApp(
|
||||
onLikeClick = clickIntents::onLikeAppClick,
|
||||
onDislikeClick = clickIntents::onDislikeAppClick,
|
||||
onCloseClick = clickIntents::onCloseRateAppWarningClick,
|
||||
),
|
||||
condition = isReadyToShowRating && readyForRateAppNotification,
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addIf(element: WalletNotification, condition: Boolean) {
|
||||
if (condition) {
|
||||
add(element = element)
|
||||
if (element is WalletNotification.Critical || element is WalletNotification.Warning) {
|
||||
readyForRateAppNotification = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_REMAINING_SIGNATURES_COUNT = 10
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ViewModelScoped
|
||||
internal class GetSingleWalletWarningsFactory @Inject constructor(
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
private val hasSingleWalletSignedHashesUseCase: HasSingleWalletSignedHashesUseCase,
|
||||
) {
|
||||
|
||||
private var readyForRateAppNotification = false
|
||||
|
||||
fun create(clickIntents: WalletClickIntentsV2): Flow<ImmutableList<WalletNotification>> {
|
||||
val userWallet = getSelectedWalletSyncUseCase().fold(
|
||||
ifLeft = {
|
||||
Timber.e("Failed to get selected wallet $it")
|
||||
return flowOf(value = persistentListOf())
|
||||
},
|
||||
ifRight = { it },
|
||||
)
|
||||
|
||||
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
|
||||
|
||||
return combine(
|
||||
flow = getPrimaryCurrencyStatusUpdatesUseCase(userWallet.walletId),
|
||||
flow2 = isReadyToShowRateAppUseCase().conflate(),
|
||||
flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(),
|
||||
) { primaryCurrencyStatus, isReadyToShowRating, isNeedToBackup ->
|
||||
readyForRateAppNotification = true
|
||||
buildList {
|
||||
addCriticalNotifications(cardTypesResolver)
|
||||
|
||||
addInformationalNotifications(cardTypesResolver)
|
||||
|
||||
addWarningNotifications(
|
||||
userWallet,
|
||||
cardTypesResolver,
|
||||
primaryCurrencyStatus,
|
||||
isNeedToBackup,
|
||||
clickIntents,
|
||||
)
|
||||
|
||||
addRateTheAppNotification(isReadyToShowRating, clickIntents)
|
||||
}.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addCriticalNotifications(cardTypesResolver: CardTypesResolver) {
|
||||
addIf(
|
||||
element = WalletNotification.Critical.DevCard,
|
||||
condition = !cardTypesResolver.isReleaseFirmwareType(),
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Critical.FailedCardValidation,
|
||||
condition = cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.isAttestationFailed(),
|
||||
)
|
||||
|
||||
cardTypesResolver.getRemainingSignatures()?.let { remainingSignatures ->
|
||||
addIf(
|
||||
element = WalletNotification.Warning.LowSignatures(count = remainingSignatures),
|
||||
condition = remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addInformationalNotifications(cardTypesResolver: CardTypesResolver) {
|
||||
addIf(
|
||||
element = WalletNotification.Informational.DemoCard,
|
||||
condition = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun MutableList<WalletNotification>.addWarningNotifications(
|
||||
userWallet: UserWallet,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
maybePrimaryCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>,
|
||||
isNeedToBackup: Boolean,
|
||||
clickIntents: WalletClickIntentsV2,
|
||||
) {
|
||||
val cryptoCurrencyStatus = maybePrimaryCurrencyStatus.fold(ifLeft = { null }, ifRight = { it })
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Warning.MissingBackup(
|
||||
onStartBackupClick = clickIntents::onAddBackupCardClick,
|
||||
),
|
||||
condition = isNeedToBackup,
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Warning.TestNetCard,
|
||||
condition = cardTypesResolver.isTestCard(),
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Warning.NetworksUnreachable,
|
||||
condition = cryptoCurrencyStatus?.value is CryptoCurrencyStatus.Unreachable,
|
||||
)
|
||||
|
||||
addNoAccountWarning(cryptoCurrencyStatus)
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Warning.NumberOfSignedHashesIncorrect(
|
||||
onCloseClick = clickIntents::onCloseAlreadySignedHashesWarningClick,
|
||||
),
|
||||
condition = hasSignedHashes(userWallet, cryptoCurrencyStatus),
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addNoAccountWarning(cryptoCurrencyStatus: CryptoCurrencyStatus?) {
|
||||
val noAccountStatus = cryptoCurrencyStatus?.value as? CryptoCurrencyStatus.NoAccount
|
||||
if (noAccountStatus != null) {
|
||||
add(
|
||||
element = WalletNotification.Informational.NoAccount(
|
||||
network = cryptoCurrencyStatus.currency.name,
|
||||
amount = noAccountStatus.amountToCreateAccount.toString(),
|
||||
symbol = cryptoCurrencyStatus.currency.symbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun hasSignedHashes(
|
||||
selectedWallet: UserWallet,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
): Boolean {
|
||||
return cryptoCurrencyStatus?.currency?.network?.let {
|
||||
hasSingleWalletSignedHashesUseCase(userWallet = selectedWallet, network = it)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.firstOrNull()
|
||||
} ?: false
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addRateTheAppNotification(
|
||||
isReadyToShowRating: Boolean,
|
||||
clickIntents: WalletClickIntentsV2,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.RateApp(
|
||||
onLikeClick = clickIntents::onLikeAppClick,
|
||||
onDislikeClick = clickIntents::onDislikeAppClick,
|
||||
onCloseClick = clickIntents::onCloseRateAppWarningClick,
|
||||
),
|
||||
condition = isReadyToShowRating && readyForRateAppNotification,
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addIf(element: WalletNotification, condition: Boolean) {
|
||||
if (condition) {
|
||||
add(element = element)
|
||||
if (element is WalletNotification.Critical || element is WalletNotification.Warning) {
|
||||
readyForRateAppNotification = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_REMAINING_SIGNATURES_COUNT = 10
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class WalletWithFundsChecker @Inject constructor(
|
||||
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
|
||||
) {
|
||||
|
||||
suspend fun check(maybeTokenList: Either<TokenListError, TokenList>) {
|
||||
val tokenList = (maybeTokenList as? Either.Right)?.value ?: return
|
||||
|
||||
val hasNonZeroWallets = when (tokenList) {
|
||||
is TokenList.GroupedByNetwork -> {
|
||||
tokenList.groups
|
||||
.flatMap(NetworkGroup::currencies)
|
||||
.hasNonZeroWallets()
|
||||
}
|
||||
is TokenList.Ungrouped -> tokenList.currencies.hasNonZeroWallets()
|
||||
is TokenList.Empty -> false
|
||||
}
|
||||
|
||||
if (hasNonZeroWallets) setWalletWithFundsFoundUseCase()
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.hasNonZeroWallets(): Boolean {
|
||||
return any {
|
||||
val amount = it.value.amount ?: return@any false
|
||||
!amount.isZero()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetWarningsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
internal class MultiWalletWarningsSubscriber(
|
||||
private val userWalletId: UserWalletId,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
|
||||
) : WalletSubscriber<ImmutableList<WalletNotification>>(name = "multi_wallet_warnings") {
|
||||
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
uiDispatcher: CoroutineContext,
|
||||
): Flow<ImmutableList<WalletNotification>> {
|
||||
return getMultiWalletWarningsFactory.create(clickIntents)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
stateHolder.update(
|
||||
SetWarningsTransformer(userWalletId = userWalletId, warnings = it),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetPrimaryCurrencyTransformer
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import java.math.BigDecimal
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
internal class PrimaryCurrencySubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : WalletSubscriber<Either<CurrencyStatusError, CryptoCurrencyStatus>>(name = "primary_currency") {
|
||||
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
uiDispatcher: CoroutineContext,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
return getPrimaryCurrencyStatusUpdatesUseCase(userWallet.walletId)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach(::updateContent)
|
||||
.onEach(::sendAnalyticsEvent)
|
||||
.onEach(::checkWalletWithFunds)
|
||||
}
|
||||
|
||||
private fun updateContent(maybeCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>) {
|
||||
val status = (maybeCurrencyStatus as? Either.Right)?.value ?: return
|
||||
|
||||
stateHolder.update(
|
||||
SetPrimaryCurrencyTransformer(
|
||||
status = status.value,
|
||||
userWallet = userWallet,
|
||||
appCurrency = appCurrency,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendAnalyticsEvent(maybeCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>) {
|
||||
val status = (maybeCurrencyStatus as? Either.Right)?.value ?: return
|
||||
|
||||
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 {
|
||||
analyticsEventHandler.send(event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded(balance = it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCardBalanceState(fiatAmount: BigDecimal?): AnalyticsParam.CardBalanceState? {
|
||||
return when {
|
||||
fiatAmount == null -> null
|
||||
fiatAmount.isZero() -> AnalyticsParam.CardBalanceState.Empty
|
||||
else -> AnalyticsParam.CardBalanceState.Full
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun checkWalletWithFunds(maybeCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>) {
|
||||
val status = (maybeCurrencyStatus as? Either.Right)?.value ?: return
|
||||
|
||||
if (status.value.amount?.isZero() == false) setWalletWithFundsFoundUseCase()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.model.TokenActionsState
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetCryptoCurrencyActionsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
internal class SingleWalletButtonsSubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
|
||||
) : WalletSubscriber<TokenActionsState>(name = "single_wallet_buttons") {
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope, uiDispatcher: CoroutineContext): Flow<TokenActionsState> {
|
||||
return channelFlow {
|
||||
getPrimaryCurrencyStatusUpdatesUseCase.collectLatest(userWalletId = userWallet.walletId) { status ->
|
||||
getCryptoCurrencyActionsUseCase(userWallet = userWallet, cryptoCurrencyStatus = status)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.firstOrNull()
|
||||
?.let { send(it) }
|
||||
}
|
||||
}
|
||||
.onEach(::updateContent)
|
||||
}
|
||||
|
||||
private fun updateContent(tokenActionsState: TokenActionsState) {
|
||||
stateHolder.update(
|
||||
SetCryptoCurrencyActionsTransformer(
|
||||
tokenActionsState = tokenActionsState,
|
||||
userWallet = userWallet,
|
||||
clickIntents = clickIntents,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetWarningsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class SingleWalletNotificationsSubscriber(
|
||||
private val userWalletId: UserWalletId,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
) : WalletSubscriber<ImmutableList<WalletNotification>>(name = "single_wallet_warnings") {
|
||||
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
uiDispatcher: CoroutineContext,
|
||||
): Flow<ImmutableList<WalletNotification>> {
|
||||
return getSingleWalletWarningsFactory.create(clickIntents)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
stateHolder.update(
|
||||
SetWarningsTransformer(userWalletId = userWalletId, warnings = it),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.GetCardTokensListUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
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.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListErrorTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class SingleWalletWithTokenListSubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
private val walletWithFundsChecker: WalletWithFundsChecker,
|
||||
private val getCardTokensListUseCase: GetCardTokensListUseCase,
|
||||
) : WalletSubscriber<Either<TokenListError, TokenList>>(name = "single_wallet_with_token_list") {
|
||||
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
uiDispatcher: CoroutineContext,
|
||||
): Flow<Either<TokenListError, TokenList>> {
|
||||
return getCardTokensListUseCase(userWalletId = userWallet.walletId)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach(::updateContent)
|
||||
.onEach(tokenListAnalyticsSender::send)
|
||||
.onEach(walletWithFundsChecker::check)
|
||||
}
|
||||
|
||||
private fun updateContent(maybeTokenList: Either<TokenListError, TokenList>) {
|
||||
stateHolder.update(
|
||||
maybeTokenList.fold(
|
||||
ifLeft = { SetTokenListErrorTransformer(userWalletId = userWallet.walletId, error = it) },
|
||||
ifRight = {
|
||||
SetTokenListTransformer(
|
||||
tokenList = it,
|
||||
userWallet = userWallet,
|
||||
appCurrency = appCurrency,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
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.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListErrorTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
typealias MaybeTokenListFlow = Flow<Either<TokenListError, TokenList>>
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenListSubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
private val walletWithFundsChecker: WalletWithFundsChecker,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
) : WalletSubscriber<Either<TokenListError, TokenList>>(name = "token_list") {
|
||||
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
uiDispatcher: CoroutineContext,
|
||||
): Flow<Either<TokenListError, TokenList>> {
|
||||
return getTokenListUseCase(userWalletId = userWallet.walletId)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach(::updateContent)
|
||||
.onEach(tokenListAnalyticsSender::send)
|
||||
.onEach(walletWithFundsChecker::check)
|
||||
}
|
||||
|
||||
private fun updateContent(maybeTokenList: Either<TokenListError, TokenList>) {
|
||||
stateHolder.update(
|
||||
maybeTokenList.fold(
|
||||
ifLeft = { SetTokenListErrorTransformer(userWalletId = userWallet.walletId, error = it) },
|
||||
ifRight = {
|
||||
SetTokenListTransformer(
|
||||
tokenList = it,
|
||||
userWallet = userWallet,
|
||||
appCurrency = appCurrency,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.txhistory.models.TxHistoryItem
|
||||
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.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountErrorTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsErrorTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
typealias MaybeTxHistoryCount = Either<TxHistoryStateError, Int>
|
||||
typealias MaybeTxHistoryItems = Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TxHistorySubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val isRefresh: Boolean,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
) : WalletSubscriber<PagingData<TxHistoryItem>>(name = "tx_history") {
|
||||
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
uiDispatcher: CoroutineContext,
|
||||
): Flow<PagingData<TxHistoryItem>> {
|
||||
return flow {
|
||||
getPrimaryCurrencyStatusUpdatesUseCase.collectLatest(userWalletId = userWallet.walletId) { 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLoadingTxHistoryState(maybeTxHistoryItemCount: MaybeTxHistoryCount, status: CryptoCurrencyStatus) {
|
||||
stateHolder.update(
|
||||
maybeTxHistoryItemCount.fold(
|
||||
ifLeft = {
|
||||
SetTxHistoryCountErrorTransformer(
|
||||
userWallet = userWallet,
|
||||
error = it,
|
||||
pendingTransactions = status.value.pendingTransactions,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
SetTxHistoryCountTransformer(
|
||||
userWalletId = userWallet.walletId,
|
||||
transactionsCount = it,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun setLoadedTxHistoryState(maybeTxHistoryItems: MaybeTxHistoryItems) {
|
||||
stateHolder.update(
|
||||
maybeTxHistoryItems.fold(
|
||||
ifLeft = {
|
||||
SetTxHistoryItemsErrorTransformer(
|
||||
userWalletId = userWallet.walletId,
|
||||
error = it,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
SetTxHistoryItemsTransformer(
|
||||
userWallet = userWallet,
|
||||
flow = it,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import timber.log.Timber
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* Component for implementation of flow subscription
|
||||
*
|
||||
* @property name unique name of subscriber
|
||||
* [T] - type of flow
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal abstract class WalletSubscriber<T>(val name: String) {
|
||||
|
||||
protected abstract fun create(coroutineScope: CoroutineScope, uiDispatcher: CoroutineContext): Flow<T>
|
||||
|
||||
fun subscribe(coroutineScope: CoroutineScope, dispatchers: CoroutineDispatcherProvider): Job {
|
||||
Timber.d("Subscribe on $name")
|
||||
return create(coroutineScope, dispatchers.main)
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(coroutineScope)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue