Updated on 2026-08-14
This commit is contained in:
parent
03691635a2
commit
e2b489f0b9
20 changed files with 144 additions and 637 deletions
|
|
@ -17,8 +17,6 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
|||
import com.tangem.datasource.api.tangemTech.models.account.toUserTokensResponse
|
||||
import com.tangem.datasource.appcurrency.AppCurrencyResponseStore
|
||||
import com.tangem.datasource.exchangeservice.hotcrypto.HotCryptoResponseStore
|
||||
import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.card.common.extensions.canHandleBlockchain
|
||||
import com.tangem.domain.card.common.extensions.canHandleToken
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
|
|
@ -43,7 +41,6 @@ import timber.log.Timber
|
|||
*
|
||||
* @property excludedBlockchains excluded blockchains
|
||||
* @property hotCryptoResponseStore store of `HotCryptoResponse`
|
||||
* @property userWalletsStore store of `UserWallet`
|
||||
* @property tangemTechApi tangem tech api
|
||||
* @property appCurrencyResponseStore store of current app currency
|
||||
* @property dispatchers dispatchers
|
||||
|
|
@ -59,8 +56,6 @@ internal class DefaultHotCryptoRepository(
|
|||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val appCurrencyResponseStore: AppCurrencyResponseStore,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val userTokensResponseStore: UserTokensResponseStore,
|
||||
private val walletAccountsFetcher: WalletAccountsFetcher,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
|
|
@ -106,12 +101,8 @@ internal class DefaultHotCryptoRepository(
|
|||
private fun getWalletsWithTokensFlow(): Flow<Map<UserWallet, List<UserTokensResponse.Token>>> {
|
||||
return userWalletsListRepository.loadAndGet().flatMapLatest { userWallets ->
|
||||
val flows = userWallets.map { userWallet ->
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
walletAccountsFetcher.get(userWalletId = userWallet.walletId).map { it.toUserTokensResponse() }
|
||||
} else {
|
||||
userTokensResponseStore.get(userWalletId = userWallet.walletId)
|
||||
}
|
||||
.map { userWallet to it?.tokens.orEmpty() }
|
||||
walletAccountsFetcher.get(userWalletId = userWallet.walletId).map { it.toUserTokensResponse() }
|
||||
.map { userWallet to it.tokens }
|
||||
}
|
||||
|
||||
combine(flows) { it.toMap() }
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
|||
import com.tangem.datasource.local.onramp.sepa.OnrampCurrentCountryByIPStore
|
||||
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStore
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.onramp.repositories.*
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
|
|
@ -110,8 +108,6 @@ internal object OnrampDataModule {
|
|||
appCurrencyResponseStore: AppCurrencyResponseStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
userTokensResponseStore: UserTokensResponseStore,
|
||||
accountsFeatureToggles: AccountsFeatureToggles,
|
||||
walletAccountsFetcher: WalletAccountsFetcher,
|
||||
): HotCryptoRepository {
|
||||
return DefaultHotCryptoRepository(
|
||||
|
|
@ -122,8 +118,6 @@ internal object OnrampDataModule {
|
|||
appCurrencyResponseStore = appCurrencyResponseStore,
|
||||
dispatchers = dispatchers,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
userTokensResponseStore = userTokensResponseStore,
|
||||
accountsFeatureToggles = accountsFeatureToggles,
|
||||
walletAccountsFetcher = walletAccountsFetcher,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import com.tangem.data.walletconnect.utils.WcNetworksConverter
|
|||
import com.tangem.data.walletconnect.utils.WcScope
|
||||
import com.tangem.datasource.di.SdkMoshi
|
||||
import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.supplier.MultiAccountListSupplier
|
||||
import com.tangem.domain.account.supplier.SingleAccountSupplier
|
||||
|
|
@ -95,7 +94,6 @@ internal object WalletConnectDataModule {
|
|||
getWallets: GetWalletsUseCase,
|
||||
wcNetworksConverter: WcNetworksConverter,
|
||||
analytics: AnalyticsEventHandler,
|
||||
accountsFeatureToggles: AccountsFeatureToggles,
|
||||
wcScope: WcScope,
|
||||
): DefaultWcSessionsManager {
|
||||
return DefaultWcSessionsManager(
|
||||
|
|
@ -104,7 +102,6 @@ internal object WalletConnectDataModule {
|
|||
getWallets = getWallets,
|
||||
wcNetworksConverter = wcNetworksConverter,
|
||||
analytics = analytics,
|
||||
accountsFeatureToggles = accountsFeatureToggles,
|
||||
scope = wcScope,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.reown.walletkit.client.Wallet
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.walletconnect.utils.WC_TAG
|
||||
import com.tangem.data.walletconnect.utils.getDappOriginUrl
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.blockaid.BlockAidVerifier
|
||||
import com.tangem.domain.walletconnect.WcAnalyticEvents
|
||||
import com.tangem.domain.walletconnect.model.*
|
||||
|
|
@ -35,7 +34,6 @@ internal class DefaultWcPairUseCase @AssistedInject constructor(
|
|||
private val sdkDelegate: WcPairSdkDelegate,
|
||||
private val blockAidVerifier: BlockAidVerifier,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
@Assisted private val pairRequest: WcPairRequest,
|
||||
) : WcPairUseCase {
|
||||
|
||||
|
|
@ -128,7 +126,7 @@ internal class DefaultWcPairUseCase @AssistedInject constructor(
|
|||
pendingSessionForSave = pendingSessionForSave,
|
||||
sessionForApprove = sessionForApprove,
|
||||
sdkSessionProposal = sdkSessionProposal,
|
||||
).map { settledSession ->
|
||||
).map { _ ->
|
||||
analytics.send(
|
||||
WcAnalyticEvents.DAppConnected(
|
||||
sessionProposal = proposalState.dAppSession,
|
||||
|
|
@ -198,11 +196,7 @@ internal class DefaultWcPairUseCase @AssistedInject constructor(
|
|||
verifyContext: Wallet.Model.VerifyContext,
|
||||
): Either<WcPairError, WcPairState.Proposal> = runCatching {
|
||||
val proposalNetwork = associateNetworksDelegate.associate(sessionProposal)
|
||||
val proposalAccountNetwork = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
associateNetworksDelegate.associateAccounts(sessionProposal)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val proposalAccountNetwork = associateNetworksDelegate.associateAccounts(sessionProposal)
|
||||
val verificationInfo = when {
|
||||
verifyContext.validation == Wallet.Model.Validation.INVALID -> CheckDAppResult.UNSAFE
|
||||
verifyContext.isScam == true -> CheckDAppResult.UNSAFE
|
||||
|
|
@ -211,7 +205,7 @@ internal class DefaultWcPairUseCase @AssistedInject constructor(
|
|||
CheckDAppResult.FAILED_TO_VERIFY
|
||||
}
|
||||
}
|
||||
val requestedNetworks = (proposalAccountNetwork ?: proposalNetwork)
|
||||
val requestedNetworks = proposalAccountNetwork
|
||||
.values.map { it.available.plus(it.required) }.flatten().toSet()
|
||||
analytics.send(
|
||||
WcAnalyticEvents.PairRequested(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.reown.walletkit.client.WalletKit
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.walletconnect.utils.*
|
||||
import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
|
|
@ -34,7 +33,6 @@ internal class DefaultWcSessionsManager(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val wcNetworksConverter: WcNetworksConverter,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val scope: WcScope,
|
||||
) : WcSessionsManager, WcSdkObserver {
|
||||
|
||||
|
|
@ -57,7 +55,6 @@ internal class DefaultWcSessionsManager(
|
|||
.flowOn(dispatchers.io)
|
||||
|
||||
private suspend fun migrateToAccountSession(inStore: Set<WcSessionDTO>): Boolean {
|
||||
if (!accountsFeatureToggles.isFeatureEnabled) return false
|
||||
if (oneTimeMigration.value) return false
|
||||
|
||||
var someMigrated = false
|
||||
|
|
@ -118,9 +115,7 @@ internal class DefaultWcSessionsManager(
|
|||
val wallet = wallets.find { it.walletId == storeSession.walletId } ?: return@mapNotNull null
|
||||
val sdkSession = inSdk.find { it.topic == storeSession.topic } ?: return@mapNotNull null
|
||||
val account = storeSession.accountId?.let { wcNetworksConverter.getAccount(it) } as? Account.CryptoPortfolio
|
||||
if (accountsFeatureToggles.isFeatureEnabled && account == null) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
?: return@mapNotNull null
|
||||
val networks = wcNetworksConverter.findWalletNetworks(wallet, account, sdkSession)
|
||||
val originUrl = storeSession.url ?: sdkSession.metaData?.url ?: ""
|
||||
WcSession(
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import com.tangem.data.walletconnect.pair.CaipNamespaceDelegate
|
|||
import com.tangem.data.walletconnect.pair.DefaultWcPairUseCase
|
||||
import com.tangem.data.walletconnect.pair.WcPairSdkDelegate
|
||||
import com.tangem.data.walletconnect.utils.WcSdkSessionConverter
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.blockaid.BlockAidVerifier
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.walletconnect.model.WcPairError
|
||||
|
|
@ -37,7 +36,6 @@ internal class DefaultWcPairUseCaseTest {
|
|||
private val analytics: AnalyticsEventHandler = mockk<AnalyticsEventHandler>(relaxed = true)
|
||||
private val sdkDelegate: WcPairSdkDelegate = mockk<WcPairSdkDelegate>()
|
||||
private val blockAidVerifier: BlockAidVerifier = mockk<BlockAidVerifier>()
|
||||
private val accountsFeatureToggles = mockk<AccountsFeatureToggles>()
|
||||
|
||||
private val url = "testUrl"
|
||||
private val source = WcPairRequest.Source.QR
|
||||
|
|
@ -117,14 +115,13 @@ internal class DefaultWcPairUseCaseTest {
|
|||
sdkDelegate = sdkDelegate,
|
||||
blockAidVerifier = blockAidVerifier,
|
||||
analytics = analytics,
|
||||
accountsFeatureToggles = accountsFeatureToggles,
|
||||
pairRequest = WcPairRequest(userWalletId = UserWalletId(""), uri = url, source = source),
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
coEvery { associateNetworksDelegate.associate(sdkProposal) } returns mapOf()
|
||||
coEvery { accountsFeatureToggles.isFeatureEnabled } returns false
|
||||
coEvery { associateNetworksDelegate.associateAccounts(sdkProposal) } returns mapOf()
|
||||
coEvery {
|
||||
caipNamespaceDelegate.associate(
|
||||
sessionProposal = sdkProposal,
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues/>
|
||||
</SmellBaseline>
|
||||
|
|
@ -31,7 +31,6 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.features.account.PortfolioSelectorComponent
|
||||
import com.tangem.features.onramp.hottokens.model.HotCryptoModel
|
||||
import com.tangem.features.onramp.hottokens.portfolio.OnrampAddToPortfolioComponent
|
||||
|
|
@ -48,38 +47,29 @@ internal class DefaultHotCryptoComponent @AssistedInject constructor(
|
|||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: HotCryptoComponent.Params,
|
||||
private val onrampAddToPortfolioComponentFactory: OnrampAddToPortfolioComponent.Factory,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
||||
addTokenComponentFactory: OnrampAddTokenComponent.Factory,
|
||||
) : HotCryptoComponent, AppComponentContext by context {
|
||||
|
||||
private val model: HotCryptoModel = getOrCreateModel(params)
|
||||
|
||||
private val portfolioSelectorComponent: PortfolioSelectorComponent? by lazy {
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
portfolioSelectorComponentFactory.create(
|
||||
context = child("portfolioSelectorComponent"),
|
||||
params = PortfolioSelectorComponent.Params(
|
||||
portfolioFetcher = requireNotNull(model.portfolioFetcher),
|
||||
controller = model.portfolioSelectorController,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
private val portfolioSelectorComponent: PortfolioSelectorComponent by lazy {
|
||||
portfolioSelectorComponentFactory.create(
|
||||
context = child("portfolioSelectorComponent"),
|
||||
params = PortfolioSelectorComponent.Params(
|
||||
portfolioFetcher = model.portfolioFetcher,
|
||||
controller = model.portfolioSelectorController,
|
||||
),
|
||||
)
|
||||
}
|
||||
private val addTokenComponent: OnrampAddTokenComponent? by lazy {
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
addTokenComponentFactory.create(
|
||||
context = child("addTokenComponent"),
|
||||
params = OnrampAddTokenComponent.Params(
|
||||
callbacks = model,
|
||||
tokenToAdd = model.hotCryptoToAddDataFlow,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
private val addTokenComponent: OnrampAddTokenComponent by lazy {
|
||||
addTokenComponentFactory.create(
|
||||
context = child("addTokenComponent"),
|
||||
params = OnrampAddTokenComponent.Params(
|
||||
callbacks = model,
|
||||
tokenToAdd = model.hotCryptoToAddDataFlow,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private val bottomSheetSlot = childSlot(
|
||||
|
|
@ -106,9 +96,7 @@ internal class DefaultHotCryptoComponent @AssistedInject constructor(
|
|||
HotCrypto(state, modifier)
|
||||
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
AddHotCryptoBottomSheet()
|
||||
}
|
||||
AddHotCryptoBottomSheet()
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -133,7 +121,7 @@ internal class DefaultHotCryptoComponent @AssistedInject constructor(
|
|||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
title = { state ->
|
||||
title = { _ ->
|
||||
AnimatedContent(targetState = contentStack.value) { stack ->
|
||||
BottomSheetTitle(
|
||||
stack = stack,
|
||||
|
|
@ -142,7 +130,7 @@ internal class DefaultHotCryptoComponent @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
},
|
||||
content = { state ->
|
||||
content = { _ ->
|
||||
AnimatedContent(targetState = contentStack.value) { stack ->
|
||||
val paddingModifier = Modifier.padding(
|
||||
start = 16.dp,
|
||||
|
|
@ -221,8 +209,8 @@ internal class DefaultHotCryptoComponent @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun contentChild(config: OnrampAddTokenRoute): ComposableContentComponent = when (config) {
|
||||
OnrampAddTokenRoute.AddToken -> requireNotNull(addTokenComponent)
|
||||
OnrampAddTokenRoute.PortfolioSelector -> requireNotNull(portfolioSelectorComponent)
|
||||
OnrampAddTokenRoute.AddToken -> addTokenComponent
|
||||
OnrampAddTokenRoute.PortfolioSelector -> portfolioSelectorComponent
|
||||
OnrampAddTokenRoute.Empty -> ComposableContentComponent.EMPTY
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
package com.tangem.features.onramp.hottokens.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.popToFirst
|
||||
import com.arkivanov.decompose.router.stack.pushNew
|
||||
|
|
@ -13,7 +10,6 @@ import com.tangem.blockchainsdk.utils.toCoinId
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.data.common.currency.getCoinId
|
||||
|
|
@ -21,17 +17,11 @@ import com.tangem.data.common.currency.getTokenId
|
|||
import com.tangem.data.common.currency.isCustomCoin
|
||||
import com.tangem.data.common.currency.isCustomToken
|
||||
import com.tangem.data.common.network.NetworkFactory
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.onramp.GetHotCryptoUseCase
|
||||
import com.tangem.domain.onramp.model.HotCryptoCurrency
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.features.account.PortfolioFetcher
|
||||
import com.tangem.features.account.PortfolioSelectorController
|
||||
import com.tangem.features.onramp.hottokens.HotCryptoComponent
|
||||
|
|
@ -51,7 +41,6 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -59,9 +48,6 @@ import javax.inject.Inject
|
|||
* Hot crypto model
|
||||
*
|
||||
* @param paramsContainer params container
|
||||
* @param getHotCryptoUseCase use case for getting hot crypto
|
||||
* @param getSelectedAppCurrencyUseCase use case for getting selected app currency
|
||||
* @property getCryptoCurrencyStatusSyncUseCase use case for getting crypto currency status by id
|
||||
* @property dispatchers dispatchers
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -70,22 +56,17 @@ import javax.inject.Inject
|
|||
@ModelScoped
|
||||
internal class HotCryptoModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
private val getHotCryptoUseCase: GetHotCryptoUseCase,
|
||||
private val callbackDelegate: HotCryptoModelCallbackDelegate,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val hotCryptoPortfolioDataLoader: HotCryptoPortfolioDataLoader,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
val portfolioSelectorController: PortfolioSelectorController,
|
||||
private val networkFactory: NetworkFactory,
|
||||
private val portfolioFetcherFactory: PortfolioFetcher.Factory,
|
||||
portfolioFetcherFactory: PortfolioFetcher.Factory,
|
||||
) : Model(), OnrampAddTokenComponent.Callbacks by callbackDelegate {
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<OnrampAddToPortfolioBSConfig> = SlotNavigation()
|
||||
|
||||
val portfolioFetcher: PortfolioFetcher?
|
||||
val portfolioFetcher: PortfolioFetcher
|
||||
val bottomSheetNavigationV2 = StackNavigation<OnrampAddTokenRoute>()
|
||||
private val addHotCryptoJob = JobHolder()
|
||||
val hotCryptoToAddDataFlow: MutableSharedFlow<AddHotCryptoData> = MutableSharedFlow(
|
||||
|
|
@ -99,53 +80,30 @@ internal class HotCryptoModel @Inject constructor(
|
|||
private val params: HotCryptoComponent.Params = paramsContainer.require()
|
||||
|
||||
init {
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
portfolioFetcher = portfolioFetcherFactory.create(
|
||||
mode = PortfolioFetcher.Mode.Wallet(params.userWalletId),
|
||||
scope = modelScope,
|
||||
)
|
||||
combineData()
|
||||
} else {
|
||||
portfolioFetcher = null
|
||||
combineDataOld()
|
||||
}
|
||||
portfolioFetcher = portfolioFetcherFactory.create(
|
||||
mode = PortfolioFetcher.Mode.Wallet(params.userWalletId),
|
||||
scope = modelScope,
|
||||
)
|
||||
combineData()
|
||||
}
|
||||
|
||||
private fun combineData() {
|
||||
combine(
|
||||
flow = hotCryptoPortfolioDataLoader.loadPortfolioData(params.userWalletId),
|
||||
flow2 = isAccountsModeEnabledUseCase.invoke(),
|
||||
transform = { data, isAccountMode ->
|
||||
hotCryptoPortfolioDataLoader.loadPortfolioData(params.userWalletId)
|
||||
.map { data ->
|
||||
HotTokenItemStateConverter(
|
||||
appCurrency = data.appCurrency,
|
||||
onItemClick = { tokenItemState, hotCryptoCurrency ->
|
||||
onItemClick = { _, hotCryptoCurrency ->
|
||||
startAddTokenFlow(currency = hotCryptoCurrency, hotCryptoPortfolioData = data)
|
||||
},
|
||||
)
|
||||
.convertList(data.allHotCrypto)
|
||||
.map(TokensListItemUM::Token)
|
||||
},
|
||||
)
|
||||
}
|
||||
.onEach { items -> state.update { HotCryptoUM(items = it.buildItems(items)) } }
|
||||
.flowOn(dispatchers.default)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun combineDataOld() {
|
||||
combine(
|
||||
flow = getSelectedAppCurrencyUseCase().map { it.getOrElse { AppCurrency.Default } },
|
||||
flow2 = getHotCryptoUseCase(params.userWalletId),
|
||||
) { appCurrency, currencies ->
|
||||
HotTokenItemStateConverter(appCurrency = appCurrency, onItemClick = ::onTokenClick)
|
||||
.convertList(currencies)
|
||||
.map(TokensListItemUM::Token)
|
||||
}
|
||||
.onEach { items ->
|
||||
state.update { HotCryptoUM(items = it.buildItems(items)) }
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun HotCryptoUM.buildItems(items: List<TokensListItemUM.Token>): ImmutableList<TokensListItemUM> =
|
||||
buildList {
|
||||
if (items.isNotEmpty()) {
|
||||
|
|
@ -163,16 +121,6 @@ internal class HotCryptoModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun onTokenClick(tokenItemState: TokenItemState, currency: HotCryptoCurrency) {
|
||||
bottomSheetNavigation.activate(
|
||||
configuration = OnrampAddToPortfolioBSConfig.AddToPortfolio(
|
||||
cryptoCurrency = currency.cryptoCurrency,
|
||||
currencyIconState = tokenItemState.iconState,
|
||||
onSuccessAdding = ::onSuccessAdding,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun startAddTokenFlow(currency: HotCryptoCurrency, hotCryptoPortfolioData: HotCryptoPortfolioData) {
|
||||
hotCryptoToAddDataFlow.resetReplayCache()
|
||||
fun closeNavigationFlow() = bottomSheetNavigationV2.replaceAll(OnrampAddTokenRoute.Empty)
|
||||
|
|
@ -200,7 +148,7 @@ internal class HotCryptoModel @Inject constructor(
|
|||
bottomSheetNavigationV2.replaceAll(OnrampAddTokenRoute.PortfolioSelector)
|
||||
|
||||
val tokenToAddStateFlow = portfolioSelectorController
|
||||
.selectedAccountWithData(requireNotNull(portfolioFetcher))
|
||||
.selectedAccountWithData(portfolioFetcher)
|
||||
.filterNotNull()
|
||||
.map { (_, selectedAccount) ->
|
||||
val cryptoCurrency = updateCryptoCurrency(
|
||||
|
|
@ -246,20 +194,6 @@ internal class HotCryptoModel @Inject constructor(
|
|||
.saveIn(addHotCryptoJob)
|
||||
}
|
||||
|
||||
private fun onSuccessAdding(id: CryptoCurrency.ID) {
|
||||
modelScope.launch {
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrencyId = id,
|
||||
)
|
||||
.onRight { status ->
|
||||
bottomSheetNavigation.dismiss()
|
||||
params.onTokenClick(status)
|
||||
}
|
||||
.onLeft { Timber.d("Unable to get CryptoCurrencyStatus[$id]: $it") }
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPortfolioSelector(hotCrypto: HotCryptoCurrency, hotCryptoPortfolioData: HotCryptoPortfolioData) {
|
||||
portfolioSelectorController.selectAccount(null)
|
||||
portfolioSelectorController.isEnabled.value = isEnabled@{ _, accountStatus ->
|
||||
|
|
|
|||
|
|
@ -1,34 +1,64 @@
|
|||
package com.tangem.features.onramp.swap.availablepairs.entity.transformers
|
||||
|
||||
import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter
|
||||
import com.tangem.common.ui.account.TokensListPortfolioItemConverter
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMData
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.utils.OnrampTokenItemStateConverterFactory
|
||||
import com.tangem.features.onramp.tokenlist.entity.utils.addHeader
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class SetNoAvailablePairsTransformer(
|
||||
private val appCurrency: AppCurrency,
|
||||
private val unavailableStatuses: List<CryptoCurrencyStatus>,
|
||||
private val accountList: Map<Account.CryptoPortfolio, List<CryptoCurrencyStatus>>,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val unavailableTokensHeaderReference: TextReference,
|
||||
private val isAccountsMode: Boolean,
|
||||
private val unavailableErrorText: TextReference,
|
||||
) : TokenListUMTransformer {
|
||||
private val unavailableConverter = OnrampTokenItemStateConverterFactory
|
||||
.createUnavailableItemConverterV2(appCurrency = appCurrency, unavailableErrorText = unavailableErrorText)
|
||||
|
||||
override fun transform(prevState: TokenListUM): TokenListUM {
|
||||
val unavailableItems = OnrampTokenItemStateConverterFactory.createUnavailableItemConverter(appCurrency)
|
||||
.convertList(unavailableStatuses)
|
||||
.map(TokensListItemUM::Token)
|
||||
val totalTokensCount = accountList.values.sumOf { it.size }
|
||||
|
||||
return prevState.copy(
|
||||
availableItems = persistentListOf(),
|
||||
unavailableItems = unavailableItems.addHeader(textReference = unavailableTokensHeaderReference),
|
||||
unavailableItems = persistentListOf(),
|
||||
tokensListData = if (isAccountsMode) {
|
||||
TokenListUMData.AccountList(
|
||||
tokensList = accountList.map { (account, cryptoCurrencies) ->
|
||||
TokensListPortfolioItemConverter(
|
||||
tokenItemUM = AccountCryptoPortfolioItemStateConverter(
|
||||
appCurrency = appCurrency,
|
||||
account = account,
|
||||
onItemClick = null,
|
||||
).convert(TotalFiatBalance.Failed),
|
||||
isExpanded = true,
|
||||
isCollapsable = false,
|
||||
tokens = unavailableConverter.convertList(cryptoCurrencies)
|
||||
.map(TokensListItemUM::Token)
|
||||
.toPersistentList(),
|
||||
).convert(Unit)
|
||||
}.toPersistentList(),
|
||||
totalTokensCount = totalTokensCount,
|
||||
)
|
||||
} else {
|
||||
TokenListUMData.TokenList(
|
||||
tokensList = accountList.flatMap { (_, cryptoCurrencies) ->
|
||||
unavailableConverter.convertList(cryptoCurrencies)
|
||||
.map(TokensListItemUM::Token)
|
||||
}.toPersistentList(),
|
||||
totalTokensCount = totalTokensCount,
|
||||
)
|
||||
},
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
warning = NotificationUM.Warning.SwapNoAvailablePair,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
package com.tangem.features.onramp.swap.availablepairs.entity.transformers
|
||||
|
||||
import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter
|
||||
import com.tangem.common.ui.account.TokensListPortfolioItemConverter
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMData
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.utils.OnrampTokenItemStateConverterFactory
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class SetNoAvailablePairsTransformerV2(
|
||||
private val appCurrency: AppCurrency,
|
||||
private val accountList: Map<Account.CryptoPortfolio, List<CryptoCurrencyStatus>>,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val isAccountsMode: Boolean,
|
||||
private val unavailableErrorText: TextReference,
|
||||
) : TokenListUMTransformer {
|
||||
private val unavailableConverter = OnrampTokenItemStateConverterFactory
|
||||
.createUnavailableItemConverterV2(appCurrency = appCurrency, unavailableErrorText = unavailableErrorText)
|
||||
|
||||
override fun transform(prevState: TokenListUM): TokenListUM {
|
||||
val totalTokensCount = accountList.values.sumOf { it.size }
|
||||
|
||||
return prevState.copy(
|
||||
availableItems = persistentListOf(),
|
||||
unavailableItems = persistentListOf(),
|
||||
tokensListData = if (isAccountsMode) {
|
||||
TokenListUMData.AccountList(
|
||||
tokensList = accountList.map { (account, cryptoCurrencies) ->
|
||||
TokensListPortfolioItemConverter(
|
||||
tokenItemUM = AccountCryptoPortfolioItemStateConverter(
|
||||
appCurrency = appCurrency,
|
||||
account = account,
|
||||
onItemClick = null,
|
||||
).convert(TotalFiatBalance.Failed),
|
||||
isExpanded = true,
|
||||
isCollapsable = false,
|
||||
tokens = unavailableConverter.convertList(cryptoCurrencies)
|
||||
.map(TokensListItemUM::Token)
|
||||
.toPersistentList(),
|
||||
).convert(Unit)
|
||||
}.toPersistentList(),
|
||||
totalTokensCount = totalTokensCount,
|
||||
)
|
||||
} else {
|
||||
TokenListUMData.TokenList(
|
||||
tokensList = accountList.flatMap { (_, cryptoCurrencies) ->
|
||||
unavailableConverter.convertList(cryptoCurrencies)
|
||||
.map(TokensListItemUM::Token)
|
||||
}.toPersistentList(),
|
||||
totalTokensCount = totalTokensCount,
|
||||
)
|
||||
},
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
warning = NotificationUM.Warning.SwapNoAvailablePair,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,10 +13,7 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
import com.tangem.core.ui.components.fields.InputManager
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.capitalize
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
|
|
@ -26,7 +23,6 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.card.common.extensions.hotWalletExcludedBlockchains
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.core.utils.getOrElse
|
||||
import com.tangem.domain.core.utils.lceContent
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
|
|
@ -41,7 +37,6 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.feature.swap.domain.GetAvailablePairsUseCase
|
||||
import com.tangem.feature.swap.domain.models.domain.LeastTokenInfo
|
||||
|
|
@ -51,9 +46,7 @@ import com.tangem.features.feed.components.market.details.portfolio.add.AddToPor
|
|||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.swap.availablepairs.AvailableSwapPairsComponent
|
||||
import com.tangem.features.onramp.swap.availablepairs.entity.transformers.SetErrorWarningTransformer
|
||||
import com.tangem.features.onramp.swap.availablepairs.entity.transformers.SetLoadingTokenItemsTransformer
|
||||
import com.tangem.features.onramp.swap.availablepairs.entity.transformers.SetNoAvailablePairsTransformer
|
||||
import com.tangem.features.onramp.swap.availablepairs.entity.transformers.SetNoAvailablePairsTransformerV2
|
||||
import com.tangem.features.onramp.swap.availablepairs.market.SwapMarketsListBatchFlowManager
|
||||
import com.tangem.features.onramp.swap.availablepairs.market.state.SwapMarketState
|
||||
import com.tangem.features.onramp.swap.entity.AccountAvailabilityUM
|
||||
|
|
@ -61,7 +54,9 @@ import com.tangem.features.onramp.swap.entity.AccountCurrencyUM
|
|||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.*
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.SetLoadingAccountTokenListTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.SetNothingToFoundStateTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateAccountTokenListTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.utils.OnrampTokenItemStateConverterFactory
|
||||
import com.tangem.features.onramp.utils.ClearSearchBarTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
|
|
@ -87,7 +82,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
private val tokenListUMController: TokenListUMController,
|
||||
private val searchManager: InputManager,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
|
|
@ -95,7 +89,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
private val getAvailablePairsUseCase: GetAvailablePairsUseCase,
|
||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase,
|
||||
private val addToPortfolioManagerFactory: AddToPortfolioManager.Factory,
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
|
|
@ -120,7 +113,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
}
|
||||
private val addToPortfolioJobHolder = JobHolder()
|
||||
|
||||
private val tokenListFlow = getTokenListUseCaseFlow()
|
||||
private val accountListFlow = getAccountListUseCaseFlow()
|
||||
private val availablePairsByNetworkFlow = MutableStateFlow<Map<LeastTokenInfo, AvailablePairsState>>(emptyMap())
|
||||
|
||||
|
|
@ -157,11 +149,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
private val visibleDefaultMarketItemIds = MutableStateFlow<List<CryptoCurrency.RawID>>(emptyList())
|
||||
|
||||
init {
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
subscribeOnUpdateStateV2()
|
||||
} else {
|
||||
subscribeOnUpdateState()
|
||||
}
|
||||
subscribeOnUpdateState()
|
||||
|
||||
initializeSearchBarCallbacks()
|
||||
subscribeOnSelectedStatusChange()
|
||||
|
|
@ -173,18 +161,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getTokenListUseCaseFlow(): SharedFlow<List<CryptoCurrencyStatus>> {
|
||||
return getTokenListUseCase.launch(userWalletId = params.userWalletId)
|
||||
.distinctUntilChanged()
|
||||
.map { maybeTokenList ->
|
||||
maybeTokenList.getOrElse(
|
||||
ifLoading = { it ?: TokenList.Empty },
|
||||
ifError = { TokenList.Empty },
|
||||
).flattenCurrencies()
|
||||
}
|
||||
.shareIn(scope = modelScope, started = SharingStarted.Eagerly, replay = 1)
|
||||
}
|
||||
|
||||
private fun getAccountListUseCaseFlow(): SharedFlow<List<AccountStatus>> {
|
||||
return singleAccountStatusListSupplier(SingleAccountStatusListProducer.Params(params.userWalletId))
|
||||
.distinctUntilChanged()
|
||||
|
|
@ -214,42 +190,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun subscribeOnUpdateState() {
|
||||
combine(
|
||||
flow = tokenListFlow,
|
||||
flow2 = getAppCurrencyAndBalanceHidingFlow(),
|
||||
flow3 = params.selectedStatus,
|
||||
flow4 = searchManager.query,
|
||||
flow5 = availablePairsByNetworkFlow
|
||||
.map { it[params.selectedStatus.value?.toLeastTokenInfo()] }
|
||||
.distinctUntilChanged(),
|
||||
) { currencies, appCurrencyAndBalanceHiding, selectedStatus, query, availablePairsState ->
|
||||
availablePairsState?.fold(
|
||||
ifLoading = { SetLoadingTokenItemsTransformer(currencies) },
|
||||
ifContent = { pairs ->
|
||||
handleContentState(
|
||||
appCurrencyAndBalanceHiding = appCurrencyAndBalanceHiding,
|
||||
currencies = currencies,
|
||||
selectedStatus = selectedStatus,
|
||||
query = query,
|
||||
availablePairs = pairs,
|
||||
)
|
||||
},
|
||||
ifError = { throwable ->
|
||||
handleErrorState(
|
||||
cause = throwable,
|
||||
networkInfo = params.selectedStatus.value?.toLeastTokenInfo(),
|
||||
currencies = currencies,
|
||||
)
|
||||
},
|
||||
)
|
||||
?: SetLoadingTokenItemsTransformer(currencies)
|
||||
}
|
||||
.onEach(tokenListUMController::update)
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeOnUpdateStateV2() {
|
||||
combine(
|
||||
flow = getAccountsAndModeFlow(),
|
||||
flow2 = getAppCurrencyAndBalanceHidingFlow(),
|
||||
|
|
@ -269,7 +209,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
)
|
||||
},
|
||||
ifContent = { pairs ->
|
||||
handleContentStateV2(
|
||||
handleContentState(
|
||||
appCurrencyAndBalanceHiding = appCurrencyAndBalanceHiding,
|
||||
accountList = accountList,
|
||||
selectedStatus = selectedStatus,
|
||||
|
|
@ -279,7 +219,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
)
|
||||
},
|
||||
ifError = { throwable ->
|
||||
handleErrorStateV2(
|
||||
handleErrorState(
|
||||
cause = throwable,
|
||||
networkInfo = params.selectedStatus.value?.toLeastTokenInfo(),
|
||||
accountList = accountList,
|
||||
|
|
@ -297,52 +237,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleContentState(
|
||||
appCurrencyAndBalanceHiding: Pair<AppCurrency, Boolean>,
|
||||
currencies: List<CryptoCurrencyStatus>,
|
||||
selectedStatus: CryptoCurrencyStatus?,
|
||||
query: String,
|
||||
availablePairs: List<SwapPairLeast>,
|
||||
): TokenListUMTransformer {
|
||||
val (appCurrency, isBalanceHidden) = appCurrencyAndBalanceHiding
|
||||
|
||||
if (availablePairs.isEmpty()) {
|
||||
return SetNoAvailablePairsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
unavailableStatuses = currencies,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
unavailableTokensHeaderReference = resourceReference(
|
||||
id = R.string.tokens_list_unavailable_to_swap_header,
|
||||
wrappedList(selectedStatus?.currency?.name?.capitalize().orEmpty()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
val filterByQueryTokenList = currencies
|
||||
.filter { it.currency != selectedStatus?.currency }
|
||||
.filterByQuery(query = query)
|
||||
|
||||
return if (query.isNotEmpty() && filterByQueryTokenList.isEmpty()) {
|
||||
SetNothingToFoundStateTransformer(
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
emptySearchMessageReference = resourceReference(
|
||||
id = R.string.action_buttons_swap_empty_search_message,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
UpdateTokenItemsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = ::onPortfolioTokenClick,
|
||||
statuses = filterByQueryTokenList.filterByAvailability(availablePairs = availablePairs),
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
unavailableTokensHeaderReference = resourceReference(
|
||||
id = R.string.tokens_list_unavailable_to_swap_header,
|
||||
wrappedList(selectedStatus?.currency?.name?.capitalize().orEmpty()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleContentStateV2(
|
||||
appCurrencyAndBalanceHiding: Pair<AppCurrency, Boolean>,
|
||||
accountList: List<AccountStatus>,
|
||||
selectedStatus: CryptoCurrencyStatus?,
|
||||
|
|
@ -371,7 +265,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
.filterValues { it.isNotEmpty() }
|
||||
|
||||
if (availablePairs.isEmpty()) {
|
||||
return SetNoAvailablePairsTransformerV2(
|
||||
return SetNoAvailablePairsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
accountList = filterByQueryAccountList,
|
||||
unavailableErrorText = resourceReference(R.string.tokens_list_unavailable_to_swap_source_header),
|
||||
|
|
@ -381,7 +275,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
}
|
||||
|
||||
return if (query.isNotEmpty() && filterByQueryAccountList.isEmpty()) {
|
||||
SetNothingToFoundStateTransformerV2(
|
||||
SetNothingToFoundStateTransformer(
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
emptySearchMessageReference = resourceReference(
|
||||
id = R.string.action_buttons_swap_empty_search_message,
|
||||
|
|
@ -400,23 +294,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleErrorState(
|
||||
cause: Throwable,
|
||||
networkInfo: LeastTokenInfo?,
|
||||
currencies: List<CryptoCurrencyStatus>,
|
||||
): SetErrorWarningTransformer {
|
||||
return SetErrorWarningTransformer(
|
||||
cause = cause,
|
||||
onRefresh = {
|
||||
modelScope.launch {
|
||||
if (networkInfo != null) {
|
||||
updateAvailablePairs(networkInfo, currencies)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleErrorStateV2(
|
||||
cause: Throwable,
|
||||
networkInfo: LeastTokenInfo?,
|
||||
accountList: List<AccountStatus>,
|
||||
|
|
@ -450,19 +327,14 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
val isAlreadyLoaded = availablePairsByNetworkFlow.value[networkInfo]?.isContent() == true
|
||||
if (isAlreadyLoaded) return@collectLatest
|
||||
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
val accountList = accountListFlow.firstOrNull() ?: return@collectLatest
|
||||
updateAvailablePairs(
|
||||
networkInfo = networkInfo,
|
||||
statuses = accountList.filterCryptoPortfolio()
|
||||
.flatMap { accountStatus ->
|
||||
accountStatus.flattenCurrencies()
|
||||
}.toSet().toList(),
|
||||
)
|
||||
} else {
|
||||
val statuses = tokenListFlow.firstOrNull() ?: return@collectLatest
|
||||
updateAvailablePairs(networkInfo = networkInfo, statuses = statuses)
|
||||
}
|
||||
val accountList = accountListFlow.firstOrNull() ?: return@collectLatest
|
||||
updateAvailablePairs(
|
||||
networkInfo = networkInfo,
|
||||
statuses = accountList.filterCryptoPortfolio()
|
||||
.flatMap { accountStatus ->
|
||||
accountStatus.flattenCurrencies()
|
||||
}.toSet().toList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -540,19 +412,6 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.filterByAvailability(
|
||||
availablePairs: List<SwapPairLeast>,
|
||||
): Map<Boolean, List<CryptoCurrencyStatus>> {
|
||||
return groupBy { status ->
|
||||
val isAvailable = availablePairs.map(SwapPairLeast::to).contains(status.toLeastTokenInfo())
|
||||
|
||||
isAvailable &&
|
||||
status.value !is CryptoCurrencyStatus.MissedDerivation &&
|
||||
status.value !is CryptoCurrencyStatus.Unreachable &&
|
||||
!status.currency.isCustom
|
||||
}
|
||||
}
|
||||
|
||||
private fun Map<Account.CryptoPortfolio, List<CryptoCurrencyStatus>>.filterByAvailability(
|
||||
availablePairs: List<SwapPairLeast>,
|
||||
): List<AccountAvailabilityUM> {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
|
|
@ -37,7 +36,6 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
) : Model() {
|
||||
|
||||
val state: StateFlow<SwapSelectTokensUM> = controller.state
|
||||
|
|
@ -77,14 +75,10 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
selectedTokenItemState = selectedTokenItemState,
|
||||
onRemoveClick = ::onRemoveFromTokenClick,
|
||||
isAccountsMode = isAccountsMode,
|
||||
account = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
getAccountCurrencyStatusUseCase.invokeSync(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = status.currency,
|
||||
).getOrNull()?.account
|
||||
} else {
|
||||
null
|
||||
},
|
||||
account = getAccountCurrencyStatusUseCase.invokeSync(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = status.currency,
|
||||
).getOrNull()?.account,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -108,14 +102,10 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
transformer = SelectToTokenTransformer(
|
||||
selectedTokenItemState = selectedTokenItemState,
|
||||
isAccountsMode = isAccountsMode,
|
||||
account = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
getAccountCurrencyStatusUseCase.invokeSync(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = status.currency,
|
||||
).getOrNull()?.account
|
||||
} else {
|
||||
null
|
||||
},
|
||||
account = getAccountCurrencyStatusUseCase.invokeSync(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = status.currency,
|
||||
).getOrNull()?.account,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ package com.tangem.features.onramp.tokenlist.entity.transformer
|
|||
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMData
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMTransformer
|
||||
|
|
@ -16,22 +14,18 @@ internal class SetNothingToFoundStateTransformer(
|
|||
|
||||
override fun transform(prevState: TokenListUM): TokenListUM {
|
||||
return prevState.copy(
|
||||
availableItems = persistentListOf(
|
||||
createGroupTitle(
|
||||
textReference = resourceReference(id = R.string.exchange_tokens_available_tokens_header),
|
||||
),
|
||||
TokensListItemUM.Text(
|
||||
id = emptySearchMessageReference.hashCode(),
|
||||
text = emptySearchMessageReference,
|
||||
),
|
||||
),
|
||||
availableItems = persistentListOf(),
|
||||
unavailableItems = persistentListOf(),
|
||||
tokensListData = TokenListUMData.EmptyList,
|
||||
tokensListData = TokenListUMData.TokenList(
|
||||
tokensList = persistentListOf(
|
||||
TokensListItemUM.Text(
|
||||
id = emptySearchMessageReference.hashCode(),
|
||||
text = emptySearchMessageReference,
|
||||
),
|
||||
),
|
||||
totalTokensCount = 0,
|
||||
),
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createGroupTitle(textReference: TextReference): TokensListItemUM.GroupTitle {
|
||||
return TokensListItemUM.GroupTitle(id = textReference.hashCode(), text = textReference)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package com.tangem.features.onramp.tokenlist.entity.transformer
|
||||
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMData
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMTransformer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class SetNothingToFoundStateTransformerV2(
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val emptySearchMessageReference: TextReference,
|
||||
) : TokenListUMTransformer {
|
||||
|
||||
override fun transform(prevState: TokenListUM): TokenListUM {
|
||||
return prevState.copy(
|
||||
availableItems = persistentListOf(),
|
||||
unavailableItems = persistentListOf(),
|
||||
tokensListData = TokenListUMData.TokenList(
|
||||
tokensList = persistentListOf(
|
||||
TokensListItemUM.Text(
|
||||
id = emptySearchMessageReference.hashCode(),
|
||||
text = emptySearchMessageReference,
|
||||
),
|
||||
),
|
||||
totalTokensCount = 0,
|
||||
),
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.core.ui.components.fields.InputManager
|
|||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
|
|
@ -16,19 +15,14 @@ import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
|||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.core.utils.getOrElse
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.tokens.GetAssetRequirementsUseCase
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.features.onramp.impl.R
|
||||
|
|
@ -36,7 +30,9 @@ import com.tangem.features.onramp.swap.entity.AccountAvailabilityUM
|
|||
import com.tangem.features.onramp.swap.entity.AccountCurrencyUM
|
||||
import com.tangem.features.onramp.tokenlist.OnrampTokenListComponent
|
||||
import com.tangem.features.onramp.tokenlist.entity.*
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.*
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.SetLoadingAccountTokenListTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.SetNothingToFoundStateTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateAccountTokenListTransformer
|
||||
import com.tangem.features.onramp.utils.ClearSearchBarTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarCallbacksTransformer
|
||||
|
|
@ -60,12 +56,10 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
private val searchManager: InputManager,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
private val rampStateManager: RampStateManager,
|
||||
private val getUserCountryUseCase: GetUserCountryUseCase,
|
||||
private val getAssetRequirementsUseCase: GetAssetRequirementsUseCase,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
) : Model() {
|
||||
|
|
@ -84,68 +78,10 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
onActiveChange = ::onSearchBarActiveChange,
|
||||
),
|
||||
)
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
subscribeOnUpdateStateV2()
|
||||
} else {
|
||||
subscribeOnUpdateState()
|
||||
}
|
||||
subscribeOnUpdateState()
|
||||
}
|
||||
|
||||
private fun subscribeOnUpdateState() {
|
||||
combine(
|
||||
flow = getTokenListUseCase.launch(userWalletId = params.userWalletId).distinctUntilChanged(),
|
||||
flow2 = getSelectedAppCurrencyUseCase().map { it.getOrElse { AppCurrency.Default } }.distinctUntilChanged(),
|
||||
flow3 = getBalanceHidingSettingsUseCase().map { it.isBalanceHidden }.distinctUntilChanged(),
|
||||
flow4 = searchManager.query,
|
||||
flow5 = hasRestrictionForSellFlow(),
|
||||
) { maybeTokenList, appCurrency, isBalanceHidden, query, hasRestrictionForSell ->
|
||||
val currencies = maybeTokenList.getOrElse(
|
||||
ifLoading = { it ?: TokenList.Empty },
|
||||
ifError = { TokenList.Empty },
|
||||
)
|
||||
.flattenCurrencies()
|
||||
|
||||
val filterByQueryTokenList = currencies
|
||||
.filterByQuery(query = query)
|
||||
|
||||
if (query.isNotEmpty() && filterByQueryTokenList.isEmpty()) {
|
||||
SetNothingToFoundStateTransformer(
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
emptySearchMessageReference = getEmptySearchMessageReference(),
|
||||
)
|
||||
} else {
|
||||
val isInsufficientBalanceForSell = if (params.filterOperation == OnrampOperation.SELL) {
|
||||
maybeTokenList.isInsufficientBalanceForSell()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
UpdateTokenItemsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = ::onTokenClick,
|
||||
statuses = filterByQueryTokenList.let { statuses ->
|
||||
if (hasRestrictionForSell || isInsufficientBalanceForSell) {
|
||||
mapOf(false to statuses)
|
||||
} else {
|
||||
statuses.filterByAvailability()
|
||||
}
|
||||
},
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
unavailableTokensHeaderReference = getUnavailableTokensHeaderReference(),
|
||||
warning = when {
|
||||
hasRestrictionForSell -> NotificationUM.Warning.SellingRegionalRestriction
|
||||
isInsufficientBalanceForSell -> NotificationUM.Warning.InsufficientBalanceForSelling
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
.onEach(::updateTokenListUM)
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeOnUpdateStateV2() {
|
||||
combine(
|
||||
flow = singleAccountStatusListSupplier(
|
||||
SingleAccountStatusListProducer.Params(params.userWalletId),
|
||||
|
|
@ -160,7 +96,7 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
|
||||
if (query.isNotEmpty() && filterByQueryAccountList.isEmpty()) {
|
||||
updateTokenListUM(
|
||||
SetNothingToFoundStateTransformerV2(
|
||||
SetNothingToFoundStateTransformer(
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
emptySearchMessageReference = getEmptySearchMessageReference(),
|
||||
),
|
||||
|
|
@ -211,16 +147,6 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun Lce<TokenListError, TokenList>.isInsufficientBalanceForSell(): Boolean {
|
||||
return if (params.filterOperation == OnrampOperation.SELL) {
|
||||
isContent {
|
||||
(it.totalFiatBalance as? TotalFiatBalance.Loaded)?.amount?.isZero() == true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun AccountStatusList.isInsufficientBalanceForSell(): Boolean {
|
||||
return if (params.filterOperation == OnrampOperation.SELL) {
|
||||
(totalFiatBalance as? TotalFiatBalance.Loaded)?.amount?.isZero() == true
|
||||
|
|
@ -268,13 +194,8 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun isFirstInitialization(prevState: TokenListUM, newState: TokenListUM): Boolean {
|
||||
return if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
prevState.tokensListData == TokenListUMData.EmptyList &&
|
||||
newState.tokensListData != TokenListUMData.EmptyList
|
||||
} else {
|
||||
prevState.availableItems.isEmpty() && prevState.unavailableItems.isEmpty() &&
|
||||
(newState.availableItems.isNotEmpty() || newState.unavailableItems.isNotEmpty())
|
||||
}
|
||||
return prevState.tokensListData == TokenListUMData.EmptyList &&
|
||||
newState.tokensListData != TokenListUMData.EmptyList
|
||||
}
|
||||
|
||||
private fun onTokenClick(tokenItemState: TokenItemState, status: CryptoCurrencyStatus) {
|
||||
|
|
@ -333,41 +254,6 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun List<CryptoCurrencyStatus>.filterByAvailability(): Map<Boolean, List<CryptoCurrencyStatus>> {
|
||||
return coroutineScope {
|
||||
map { status ->
|
||||
async {
|
||||
val isOperationAvailable = checkAvailabilityByOperation(status = status)
|
||||
val isNotMissedDerivation = status.value !is CryptoCurrencyStatus.MissedDerivation
|
||||
val isNotLoading = status.value !is CryptoCurrencyStatus.Loading
|
||||
|
||||
val requirements = getAssetRequirementsUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
currency = status.currency,
|
||||
).getOrNull()
|
||||
|
||||
val isAvailableForBuy = rampStateManager.checkAssetRequirements(requirements)
|
||||
val isNotUnreachable = status.value !is CryptoCurrencyStatus.Unreachable
|
||||
|
||||
val isAvailable = when (params.filterOperation) {
|
||||
OnrampOperation.BUY -> {
|
||||
isAvailableForBuy
|
||||
} // unreachable state is available for Buy operation
|
||||
OnrampOperation.SELL -> isNotUnreachable
|
||||
OnrampOperation.SWAP -> {
|
||||
isNotUnreachable && isAvailableForBuy
|
||||
}
|
||||
}
|
||||
|
||||
status to (isOperationAvailable && isNotMissedDerivation && isNotLoading && isAvailable)
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.groupBy(Pair<CryptoCurrencyStatus, Boolean>::second)
|
||||
.mapValues { it.value.map(Pair<CryptoCurrencyStatus, Boolean>::first) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun AccountCryptoList.filterByAvailability(): List<AccountAvailabilityUM> {
|
||||
return coroutineScope {
|
||||
map { (account, currencies) ->
|
||||
|
|
|
|||
|
|
@ -27,12 +27,10 @@
|
|||
<ID>MultilineLambdaItParameter:WcSwitchNetworkModel.kt$WcSwitchNetworkModel${ if (it.isExistInWcSession) { router.pop() } else { showErrorDialog(HandleMethodError.RequiredNetwork(it.network.name)) } }</ID>
|
||||
<ID>NamedArguments:WcAddEthereumChainModalBottomSheetContent.kt$WcAddEthereumChainModalBottomSheetContent(state, {}, {}, {})</ID>
|
||||
<ID>NamedArguments:WcAlertsFactory.kt$WcAlertsFactory$createMaliciousDAppAlert(alertType.description, alertType.onClick, alertType.iconType, alertType.iconBgType)</ID>
|
||||
<ID>NamedArguments:WcPairModel.kt$WcPairModel$handlePairState( pairState, portfolios, selected, isAccountMode, )</ID>
|
||||
<ID>NamedArguments:WcSendTransactionModel.kt$WcSendTransactionModel$buildUiState(securityCheck, useCase, signState, isApprovalMethod)</ID>
|
||||
<ID>NestedScopeFunctions:WcSendAndReceiveBlockAidUiConverter.kt$WcSendAndReceiveBlockAidUiConverter$let { spendAllowanceUMConverter.convert( WcSpendAllowanceUMConverter.Input( approvedAmount = it, onLearnMoreClick = value.onApproveLearnMoreClick, ), ) }</ID>
|
||||
<ID>NoNameShadowing:WcNavigationUtils.kt$model</ID>
|
||||
<ID>NullCheckOnMutableProperty:WcCommonTransactionComponentDelegate.kt$WcCommonTransactionComponentDelegate$if (contentStack != null) { val content by contentStack!!.subscribeAsState() BackHandler(onBack = ::onChildBack) content.active.instance.BottomSheet() }</ID>
|
||||
<ID>NullableBooleanCheck:WcPairModel.kt$WcPairModel$isAccountMode ?: false</ID>
|
||||
<ID>NullableToStringCall:WcEstimatedWalletChangeUMConverter.kt$WcEstimatedWalletChangeUMConverter$${value.sign}</ID>
|
||||
<ID>ReusedModifierInstance:DefaultWalletConnectEntryComponent.kt$DefaultWalletConnectEntryComponent$Content(modifier = modifier)</ID>
|
||||
<ID>ReusedModifierInstance:WcAppInfoBS.kt$Box( modifier = modifier .padding(start = 48.dp) .border( width = 2.dp, color = TangemTheme.colors.background.action, shape = CircleShape, ) .padding(2.dp) .background(color = TangemTheme.colors.background.action) .size(20.dp) .clip(CircleShape) .background(color = TangemTheme.colors.icon.primary1.copy(alpha = 0.1F)), ) { Text( modifier = Modifier.align(Alignment.Center), text = "+$remainingCount", style = TangemTheme.typography.overline, color = TangemTheme.colors.text.secondary, ) }</ID>
|
||||
|
|
@ -46,7 +44,6 @@
|
|||
<ID>UnsafeCallOnNullableType:WcPairComponent.kt$WcPairComponent$model.portfolioFetcher!!</ID>
|
||||
<ID>UnsafeCallOnNullableType:WcSignTransactionComponent.kt$WcSignTransactionComponent$content!!</ID>
|
||||
<ID>UnsafeCallOnNullableType:WcTransactionRequestInfoComponent.kt$WcTransactionRequestInfoComponent$content!!</ID>
|
||||
<ID>UseEmptyCounterpart:WcPairModel.kt$WcPairModel$setOf<Network>()</ID>
|
||||
<ID>UseOrEmpty:WcSpendAllowanceUMConverter.kt$WcSpendAllowanceUMConverter$value.approvedAmount.amount?.currencySymbol ?: ""</ID>
|
||||
<ID>UseOrEmpty:WcTransactionCheckErrorItem.kt$notification.text?.resolveReference() ?: ""</ID>
|
||||
</CurrentIssues>
|
||||
|
|
|
|||
|
|
@ -15,11 +15,9 @@ import com.tangem.core.decompose.navigation.inner.InnerRouter
|
|||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.features.account.PortfolioSelectorComponent
|
||||
import com.tangem.features.walletconnect.connections.components.WcSelectNetworksComponent.*
|
||||
import com.tangem.features.walletconnect.connections.components.WcSelectWalletComponent.*
|
||||
import com.tangem.features.walletconnect.connections.model.WcPairModel
|
||||
import com.tangem.features.walletconnect.connections.routes.WcAppInfoRoutes
|
||||
import com.tangem.features.walletconnect.connections.routes.WcAppInfoRoutes.Alert
|
||||
|
|
@ -115,7 +113,7 @@ internal class WcPairComponent(
|
|||
WcAppInfoRoutes.PortfolioSelector -> portfolioSelectorComponentFactory.create(
|
||||
context = appComponentContext,
|
||||
params = PortfolioSelectorComponent.Params(
|
||||
portfolioFetcher = model.portfolioFetcher!!,
|
||||
portfolioFetcher = model.portfolioFetcher,
|
||||
bsCallback = model.portfolioSelectorCallback,
|
||||
controller = model.selectorController,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import com.tangem.core.ui.message.DialogMessage
|
|||
import com.tangem.core.ui.message.EventMessageAction
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.supplier.MultiAccountListSupplier
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.qrscanning.models.QrResultSource
|
||||
|
|
@ -55,7 +54,6 @@ internal class WcConnectionsModel @Inject constructor(
|
|||
private val wcDisconnectUseCase: WcDisconnectUseCase,
|
||||
private val multiAccountListSupplier: MultiAccountListSupplier,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val wcPairService: WcPairService,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
analytics: AnalyticsEventHandler,
|
||||
|
|
@ -70,11 +68,7 @@ internal class WcConnectionsModel @Inject constructor(
|
|||
init {
|
||||
analytics.send(WcAnalyticEvents.ScreenOpened())
|
||||
listenQrUpdates()
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
listenWcSessions()
|
||||
} else {
|
||||
listenWcSessionsOld()
|
||||
}
|
||||
listenWcSessions()
|
||||
}
|
||||
|
||||
private fun listenQrUpdates() {
|
||||
|
|
@ -98,21 +92,6 @@ internal class WcConnectionsModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun listenWcSessionsOld() {
|
||||
wcSessionsUseCase.invoke()
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach { sessionsMap ->
|
||||
uiState.update(
|
||||
WcSessionsTransformer(
|
||||
sessionsMap = sessionsMap,
|
||||
openAppInfoModal = ::openAppInfoModal,
|
||||
),
|
||||
)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun listenWcSessions() {
|
||||
combine(
|
||||
flow = wcSessionsUseCase.invoke().distinctUntilChanged(),
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.message.ToastMessage
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.producer.SingleAccountListProducer
|
||||
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
|
|
@ -75,7 +74,6 @@ internal class WcPairModel @Inject constructor(
|
|||
private val messageSender: UiMessageSender,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
val selectorController: PortfolioSelectorController,
|
||||
private val singleAccountListSupplier: SingleAccountListSupplier,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
|
|
@ -95,7 +93,10 @@ internal class WcPairModel @Inject constructor(
|
|||
)
|
||||
|
||||
val stackNavigation = StackNavigation<WcAppInfoRoutes>()
|
||||
val portfolioFetcher: PortfolioFetcher?
|
||||
val portfolioFetcher: PortfolioFetcher = portfolioFetcherFactory.create(
|
||||
mode = PortfolioFetcher.Mode.All(isOnlyMultiCurrency = true),
|
||||
scope = modelScope,
|
||||
)
|
||||
val portfolioSelectorCallback = object : PortfolioSelectorComponent.BottomSheetCallback {
|
||||
override val onDismiss: () -> Unit = { stackNavigation.pop() }
|
||||
override val onBack: () -> Unit = { stackNavigation.pop() }
|
||||
|
|
@ -110,32 +111,23 @@ internal class WcPairModel @Inject constructor(
|
|||
)
|
||||
private var proposalNetwork by Delegates.notNull<WcSessionProposal.ProposalNetwork>()
|
||||
private var sessionProposal by Delegates.notNull<WcSessionProposal>()
|
||||
private var additionallyEnabledNetworks = setOf<Network>()
|
||||
private var additionallyEnabledNetworks = emptySet<Network>()
|
||||
private val dAppVerifiedStateConverter = WcDAppVerifiedStateConverter(onVerifiedClick = ::showVerifiedAlert)
|
||||
|
||||
val appInfoUiState: StateFlow<WcAppInfoUM>
|
||||
field = MutableStateFlow<WcAppInfoUM>(createLoadingState())
|
||||
|
||||
init {
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
portfolioFetcher = portfolioFetcherFactory.create(
|
||||
mode = PortfolioFetcher.Mode.All(isOnlyMultiCurrency = true),
|
||||
scope = modelScope,
|
||||
)
|
||||
modelScope.launch {
|
||||
val params = SingleAccountListProducer.Params(params.userWalletId)
|
||||
val accountList = singleAccountListSupplier.getSyncOrNull(params)
|
||||
if (accountList == null) {
|
||||
router.pop()
|
||||
return@launch
|
||||
}
|
||||
val firstAccount = accountList.accounts.first()
|
||||
selectorController.selectAccount(firstAccount.accountId)
|
||||
combineFlows(portfolioFetcher)
|
||||
modelScope.launch {
|
||||
val params = SingleAccountListProducer.Params(params.userWalletId)
|
||||
val accountList = singleAccountListSupplier.getSyncOrNull(params)
|
||||
if (accountList == null) {
|
||||
router.pop()
|
||||
return@launch
|
||||
}
|
||||
} else {
|
||||
portfolioFetcher = null
|
||||
loadDAppInfo()
|
||||
val firstAccount = accountList.accounts.first()
|
||||
selectorController.selectAccount(firstAccount.accountId)
|
||||
combineFlows(portfolioFetcher)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,22 +143,16 @@ internal class WcPairModel @Inject constructor(
|
|||
flow4 = isAccountsModeEnabledUseCase(),
|
||||
transform = { portfolios, selected, pairState, isAccountMode ->
|
||||
handlePairState(
|
||||
pairState,
|
||||
portfolios,
|
||||
selected,
|
||||
isAccountMode,
|
||||
pairState = pairState,
|
||||
portfolios = portfolios,
|
||||
selected = selected,
|
||||
isAccountMode = isAccountMode,
|
||||
)
|
||||
},
|
||||
)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun loadDAppInfo() {
|
||||
wcPairUseCase()
|
||||
.onEach { pairState -> handlePairState(pairState) }
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private suspend fun handlePairState(
|
||||
pairState: WcPairState,
|
||||
portfolios: PortfolioFetcher.Data? = null,
|
||||
|
|
@ -193,7 +179,7 @@ internal class WcPairModel @Inject constructor(
|
|||
)
|
||||
processError(pairState.error)
|
||||
}
|
||||
is WcPairState.Loading -> appInfoUiState.update { createLoadingState(isAccountMode ?: false) }
|
||||
is WcPairState.Loading -> appInfoUiState.update { createLoadingState(isAccountMode == true) }
|
||||
is WcPairState.Proposal -> handleProposalState(
|
||||
pairState = pairState,
|
||||
portfolios = portfolios,
|
||||
|
|
@ -225,7 +211,7 @@ internal class WcPairModel @Inject constructor(
|
|||
} else {
|
||||
val portfolioSelectRow = tryToCreatePortfolioSelectRow(selected, portfolios)
|
||||
if (proposalAccountNetwork != null) {
|
||||
selectorController.isEnabled.value = { wallet, account ->
|
||||
selectorController.isEnabled.value = { _, account ->
|
||||
proposalAccountNetwork.contains(account.account.accountId)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue