Updated on 2026-08-14

This commit is contained in:
Tangem 2023-08-31 16:58:05 +03:00
parent dc4e8c740b
commit fefe37a890
23 changed files with 285 additions and 140 deletions

View file

@ -190,6 +190,7 @@ class TapApplication : Application(), ImageLoaderFactory {
scanCardProcessor = scanCardProcessor,
appCurrencyRepository = appCurrencyRepository,
walletManagersFacade = walletManagersFacade,
appStateHolder = appStateHolder,
),
),
)

View file

@ -131,6 +131,8 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
sellService = makeSellExchangeService(config),
primaryRules = CardExchangeRules(cardProvider),
)
// TODO: for refactoring (after remove old design refactor CurrencyExchangeManager and use 1 instance)
store.state.daggerGraphState.get(DaggerGraphState::appStateHolder).exchangeService = exchangeManager
store.dispatchOnMain(GlobalAction.ExchangeManager.Init.Success(exchangeManager))
store.dispatchOnMain(GlobalAction.ExchangeManager.Update)
}

View file

@ -3,8 +3,11 @@ package com.tangem.tap.di
import android.content.Context
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.exchange.RampStateManager
import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
import com.tangem.tap.network.exchangeServices.DefaultRampManager
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.userTokensRepository
import dagger.Module
import dagger.Provides
@ -40,4 +43,10 @@ internal object ActivityModule {
),
)
}
@Provides
@Singleton
fun provideDefaultRampManager(appStateHolder: AppStateHolder): RampStateManager {
return DefaultRampManager(appStateHolder.exchangeService)
}
}

View file

@ -1,7 +1,9 @@
package com.tangem.tap.di.domain
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.MarketCryptoCurrencyRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -108,8 +110,10 @@ internal object TokensDomainModule {
@Provides
@ViewModelScoped
fun provideGetCryptoCurrencyActionsUseCase(
rampStateManager: RampStateManager,
marketCryptoCurrencyRepository: MarketCryptoCurrencyRepository,
dispatchers: CoroutineDispatcherProvider,
): GetCryptoCurrencyActionsUseCase {
return GetCryptoCurrencyActionsUseCase(dispatchers)
return GetCryptoCurrencyActionsUseCase(rampStateManager, marketCryptoCurrencyRepository, dispatchers)
}
}

View file

@ -1,105 +0,0 @@
package com.tangem.tap.domain.tokens
import com.squareup.moshi.JsonAdapter
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.services.Result
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.datasource.asset.AssetReader
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
class LoadAvailableCoinsService(
private val tangemTechApi: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
private val assetReader: AssetReader,
) {
private val currenciesAdapter: JsonAdapter<CurrenciesFromJson> =
MoshiConverter.networkMoshi.adapter(CurrenciesFromJson::class.java)
suspend fun getSupportedTokens(
isTestNet: Boolean,
supportedBlockchains: List<Blockchain>,
page: Int,
searchInput: String?,
): Result<LoadedCoins> {
if (isTestNet) {
return Result.Success(
LoadedCoins(
currencies = getTestnetCoins().filter(searchInput),
moreAvailable = false,
),
)
}
val offset = page * LOAD_PER_PAGE
return when (val result = loadCoins(supportedBlockchains, offset, searchInput)) {
is Result.Success -> {
val data = result.data
Result.Success(
LoadedCoins(
currencies = data.coins.map {
Currency.fromCoinResponse(currency = it, imageHost = data.imageHost)
},
moreAvailable = data.total > offset + LOAD_PER_PAGE,
),
)
}
is Result.Failure -> {
Result.Failure(result.error)
}
}
}
private suspend fun loadCoins(
supportedBlockchains: List<Blockchain>,
offset: Int,
searchInput: String?,
): Result<CoinsResponse> {
return withContext(dispatchers.io) {
runCatching {
tangemTechApi.getCoins(
networkIds = supportedBlockchains.joinToString(
separator = ",",
transform = Blockchain::toNetworkId,
),
active = true,
searchText = searchInput,
offset = offset,
limit = LOAD_PER_PAGE,
)
}.fold(
onSuccess = { Result.Success(it) },
onFailure = { Result.Failure(it) },
)
}
}
private fun getTestnetCoins(): List<Currency> {
val json = assetReader.readJson(FILE_NAME_TESTNET_COINS)
return currenciesAdapter.fromJson(json)!!.coins
.map { Currency.fromJsonObject(it) }
}
private fun List<Currency>.filter(searchInput: String?): List<Currency> {
if (searchInput.isNullOrBlank()) return this
return filter { currency ->
currency.symbol.contains(searchInput, ignoreCase = true) ||
currency.name.contains(searchInput, ignoreCase = true)
}
}
private companion object {
const val LOAD_PER_PAGE = 100
const val FILE_NAME_TESTNET_COINS = "testnet_tokens"
}
}
data class LoadedCoins(
val currencies: List<Currency>,
val moreAvailable: Boolean,
)

View file

@ -1,13 +1,15 @@
package com.tangem.tap.features.wallet.converters
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.store
import com.tangem.utils.converter.Converter
import com.tangem.utils.converter.TwoWayConverter
internal class CryptoCurrencyConverter : Converter<Currency, CryptoCurrency> {
internal class CryptoCurrencyConverter : TwoWayConverter<Currency, CryptoCurrency> {
private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory() }
@ -40,4 +42,26 @@ internal class CryptoCurrencyConverter : Converter<Currency, CryptoCurrency> {
)
}
}
override fun convertBack(value: CryptoCurrency): Currency {
val blockchain = Blockchain.fromId(value.network.id.value)
if (blockchain == Blockchain.Unknown) error("CryptoCurrencyConverter convertBack Unknown blockchain")
return when (value) {
is CryptoCurrency.Coin -> Currency.Blockchain(
blockchain = blockchain,
derivationPath = value.derivationPath,
)
is CryptoCurrency.Token -> Currency.Token(
token = Token(
name = value.name,
symbol = value.symbol,
contractAddress = value.contractAddress,
decimals = value.decimals,
id = value.id.value,
),
blockchain = blockchain,
derivationPath = value.derivationPath,
)
}
}
}

View file

@ -0,0 +1,21 @@
package com.tangem.tap.network.exchangeServices
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.tap.features.wallet.converters.CryptoCurrencyConverter
class DefaultRampManager(private val exchangeService: ExchangeService?) : RampStateManager {
private val cryptoCurrencyConverter = CryptoCurrencyConverter()
override fun availableForBuy(cryptoCurrency: CryptoCurrency): Boolean {
return exchangeService?.availableForBuy(
currency = cryptoCurrencyConverter.convertBack(cryptoCurrency),
) ?: false
}
override fun availableForSell(cryptoCurrency: CryptoCurrency): Boolean {
return exchangeService?.availableForSell(
currency = cryptoCurrencyConverter.convertBack(cryptoCurrency),
) ?: false
}
}

View file

@ -14,6 +14,7 @@ import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.walletStores.WalletStoresManager
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.network.exchangeServices.ExchangeService
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import org.rekotlin.Action
@ -45,6 +46,7 @@ class AppStateHolder @Inject constructor() : WalletsStateHolder, ReduxNavControl
var tangemSdkManager: TangemSdkManager? = null
var walletStoresManager: WalletStoresManager? = null
var appFiatCurrency: FiatCurrency = FiatCurrency.Default
var exchangeService: ExchangeService? = null
fun getActualCard(): CardDTO? {
return scanResponse?.card

View file

@ -16,6 +16,7 @@ import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectRepository
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
import com.tangem.tap.proxy.AppStateHolder
import org.rekotlin.StateType
data class DaggerGraphState(
@ -35,6 +36,7 @@ data class DaggerGraphState(
val cardSdkConfigRepository: CardSdkConfigRepository? = null,
val appCurrencyRepository: AppCurrencyRepository? = null,
val walletManagersFacade: WalletManagersFacade? = null,
val appStateHolder: AppStateHolder? = null,
) : StateType {
inline fun <reified T> get(getDependency: DaggerGraphState.() -> T?): T {

View file

@ -0,0 +1,21 @@
package com.tangem.datasource.di
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.token.DefaultUserMarketCoinsStore
import com.tangem.datasource.local.token.UserMarketCoinsStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object MarketCoinsStoreModule {
@Provides
@Singleton
fun provideUserMarketCoinsStore(): UserMarketCoinsStore {
return DefaultUserMarketCoinsStore(dataStore = RuntimeDataStore())
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.datasource.local.token
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.domain.wallets.models.UserWalletId
internal class DefaultUserMarketCoinsStore(
private val dataStore: StringKeyDataStore<CoinsResponse>,
) : UserMarketCoinsStore {
override suspend fun getSyncOrNull(userWalletId: UserWalletId): CoinsResponse? {
return dataStore.getSyncOrNull(userWalletId.stringValue)
}
override suspend fun store(userWalletId: UserWalletId, item: CoinsResponse) {
dataStore.store(userWalletId.stringValue, item)
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.datasource.local.token
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.domain.wallets.models.UserWalletId
interface UserMarketCoinsStore {
suspend fun getSyncOrNull(userWalletId: UserWalletId): CoinsResponse?
suspend fun store(userWalletId: UserWalletId, item: CoinsResponse)
}

View file

@ -2,14 +2,17 @@ package com.tangem.data.tokens.di
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.tokens.repository.DefaultCurrenciesRepository
import com.tangem.data.tokens.repository.DefaultMarketCryptoCurrencyRepository
import com.tangem.data.tokens.repository.DefaultNetworksRepository
import com.tangem.data.tokens.repository.DefaultQuotesRepository
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore
import com.tangem.datasource.local.quote.QuotesStore
import com.tangem.datasource.local.token.UserMarketCoinsStore
import com.tangem.datasource.local.token.UserTokensStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.MarketCryptoCurrencyRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
@ -30,10 +33,18 @@ internal object TokensDataModule {
tangemTechApi: TangemTechApi,
userTokensStore: UserTokensStore,
userWalletsStore: UserWalletsStore,
userMarketCoinsStore: UserMarketCoinsStore,
cacheRegistry: CacheRegistry,
dispatchers: CoroutineDispatcherProvider,
): CurrenciesRepository {
return DefaultCurrenciesRepository(tangemTechApi, userTokensStore, userWalletsStore, cacheRegistry, dispatchers)
return DefaultCurrenciesRepository(
tangemTechApi = tangemTechApi,
userTokensStore = userTokensStore,
userWalletsStore = userWalletsStore,
userMarketCoinsStore = userMarketCoinsStore,
cacheRegistry = cacheRegistry,
dispatchers = dispatchers,
)
}
@Provides
@ -46,11 +57,11 @@ internal object TokensDataModule {
dispatchers: CoroutineDispatcherProvider,
): QuotesRepository {
return DefaultQuotesRepository(
tangemTechApi,
quotesStore,
selectedAppCurrencyStore,
cacheRegistry,
dispatchers,
tangemTechApi = tangemTechApi,
quotesStore = quotesStore,
selectedAppCurrencyStore = selectedAppCurrencyStore,
cacheRegistry = cacheRegistry,
dispatchers = dispatchers,
)
}
@ -64,11 +75,19 @@ internal object TokensDataModule {
dispatchers: CoroutineDispatcherProvider,
): NetworksRepository {
return DefaultNetworksRepository(
walletManagersFacade,
userWalletsStore,
userTokensStore,
cacheRegistry,
dispatchers,
walletManagersFacade = walletManagersFacade,
userWalletsStore = userWalletsStore,
userTokensStore = userTokensStore,
cacheRegistry = cacheRegistry,
dispatchers = dispatchers,
)
}
@Provides
@Singleton
fun provideDefaultMarketCoinsRepository(
userMarketCoinsStore: UserMarketCoinsStore,
): MarketCryptoCurrencyRepository {
return DefaultMarketCryptoCurrencyRepository(userMarketCoinsStore)
}
}

View file

@ -6,6 +6,7 @@ import com.tangem.data.tokens.utils.ResponseCurrenciesFactory
import com.tangem.data.tokens.utils.UserTokensResponseFactory
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.local.token.UserMarketCoinsStore
import com.tangem.datasource.local.token.UserTokensStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.common.util.derivationStyleProvider
@ -27,6 +28,7 @@ internal class DefaultCurrenciesRepository(
private val tangemTechApi: TangemTechApi,
private val userTokensStore: UserTokensStore,
private val userWalletsStore: UserWalletsStore,
private val userMarketCoinsStore: UserMarketCoinsStore,
private val cacheRegistry: CacheRegistry,
private val dispatchers: CoroutineDispatcherProvider,
) : CurrenciesRepository {
@ -172,6 +174,7 @@ internal class DefaultCurrenciesRepository(
val response = tangemTechApi.getUserTokens(userWallet.walletId.stringValue)
userTokensStore.store(userWallet.walletId, response)
fetchUserMarketCoinsByIds(userWallet.walletId, response)
} catch (e: Throwable) {
handleFetchTokensErrorOrThrow(userWallet, e)
}
@ -182,6 +185,17 @@ internal class DefaultCurrenciesRepository(
tangemTechApi.saveUserTokens(userWalletId.stringValue, response)
}
private suspend fun fetchUserMarketCoinsByIds(userWalletId: UserWalletId, userTokens: UserTokensResponse) {
try {
val response = tangemTechApi.getCoins(
networkIds = userTokens.tokens.joinToString(separator = ",") { it.networkId },
)
userMarketCoinsStore.store(userWalletId, response)
} catch (e: Throwable) {
Timber.e("Unable to fetch user market coins for: ${userWalletId.stringValue} ${e.message}")
}
}
private suspend fun handleFetchTokensErrorOrThrow(userWallet: UserWallet, error: Throwable) {
val errorMessage = error.message ?: throw error

View file

@ -0,0 +1,18 @@
package com.tangem.data.tokens.repository
import com.tangem.datasource.local.token.UserMarketCoinsStore
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.tokens.repository.MarketCryptoCurrencyRepository
import com.tangem.domain.wallets.models.UserWalletId
class DefaultMarketCryptoCurrencyRepository(
private val userMarketCoinsStore: UserMarketCoinsStore,
) : MarketCryptoCurrencyRepository {
override suspend fun isExchangeable(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID): Boolean {
return userMarketCoinsStore.getSyncOrNull(userWalletId)?.coins
?.firstOrNull { it.id == cryptoCurrencyId.rawCurrencyId }
?.networks
?.firstOrNull { it.networkId == cryptoCurrencyId.rawNetworkId }?.exchangeable ?: false
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.domain.exchange
import com.tangem.domain.tokens.models.CryptoCurrency
/**
* Manager that holds info about available actions as Sell and Buy
*/
interface RampStateManager {
fun availableForBuy(cryptoCurrency: CryptoCurrency): Boolean
fun availableForSell(cryptoCurrency: CryptoCurrency): Boolean
}

View file

@ -1,13 +1,19 @@
plugins {
alias(deps.plugins.kotlin.jvm)
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
id("configuration")
}
android {
namespace = "com.tangem.domain.tokens"
}
dependencies {
/** Project - Domain */
implementation(projects.domain.core)
implementation(projects.domain.models)
implementation(projects.domain.legacy)
implementation(projects.domain.tokens.models)
implementation(projects.domain.wallets.models)
implementation(projects.domain.appCurrency.models)

View file

@ -93,6 +93,8 @@ sealed class CryptoCurrency : Serializable {
val rawCurrencyId: String? = (suffix as? Suffix.RawID)?.rawId
val rawNetworkId: String = networkId.value
/**
* Represents the different types of prefixes that can be associated with a cryptocurrency ID.
* These prefixes can help in quickly categorizing the type of cryptocurrency.

View file

@ -1,34 +1,84 @@
package com.tangem.domain.tokens
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.tokens.repository.MarketCryptoCurrencyRepository
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
/**
* Use case to determine which TokenActions are available for a [CryptoCurrency]
*
* @property rampManager Ramp manager to check ramp availability
*/
class GetCryptoCurrencyActionsUseCase(
private val rampManager: RampStateManager,
private val marketCryptoCurrencyRepository: MarketCryptoCurrencyRepository,
private val dispatchers: CoroutineDispatcherProvider,
) {
operator fun invoke(userWalletId: UserWalletId, tokenId: String): Flow<TokenActionsState> {
operator fun invoke(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Flow<TokenActionsState> {
return flow {
emit(getMockState(userWalletId, tokenId))
val actionStates = createTokenActionsState(userWalletId, cryptoCurrency)
emit(actionStates)
}.flowOn(dispatchers.io)
}
// TODO replace by real data
private fun getMockState(userWalletId: UserWalletId, tokenId: String): TokenActionsState {
private suspend fun createTokenActionsState(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): TokenActionsState {
return TokenActionsState(
walletId = userWalletId,
tokenId = tokenId,
states = listOf(
TokenActionsState.ActionState.Buy(true),
TokenActionsState.ActionState.Send(true),
TokenActionsState.ActionState.Receive(true),
TokenActionsState.ActionState.Sell(true),
TokenActionsState.ActionState.Swap(true),
),
cryptoCurrencyId = cryptoCurrency.id,
states = createListOfActions(userWalletId, cryptoCurrency),
)
}
/**
* Creates list of action for expected order
* Actions priority: [Buy Send Receive Sell Swap]
*/
private suspend fun createListOfActions(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): List<TokenActionsState.ActionState> {
return buildList {
// todo add check available in swap 1inch etc if backend doen't handle it
if (marketCryptoCurrencyRepository.isExchangeable(userWalletId, cryptoCurrency.id) &&
!isCustomToken(cryptoCurrency)
) {
addFirst(TokenActionsState.ActionState.Swap(true))
} else {
add(TokenActionsState.ActionState.Swap(false))
}
if (rampManager.availableForSell(cryptoCurrency)) {
addFirst(TokenActionsState.ActionState.Sell(true))
} else {
add(TokenActionsState.ActionState.Sell(false))
}
addFirst(TokenActionsState.ActionState.Receive(true))
addFirst(TokenActionsState.ActionState.Send(true))
if (rampManager.availableForBuy(cryptoCurrency)) {
addFirst(TokenActionsState.ActionState.Buy(true))
} else {
add(TokenActionsState.ActionState.Buy(false))
}
}
}
private fun isCustomToken(currency: CryptoCurrency): Boolean {
return currency is CryptoCurrency.Token && currency.isCustom
}
private fun <T> MutableList<T>.addFirst(item: T) {
this.add(0, item)
}
}

View file

@ -1,10 +1,11 @@
package com.tangem.domain.tokens.model
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
data class TokenActionsState(
val walletId: UserWalletId,
val tokenId: String,
val cryptoCurrencyId: CryptoCurrency.ID,
val states: List<ActionState>,
) {

View file

@ -0,0 +1,12 @@
package com.tangem.domain.tokens.repository
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
/**
* MarketCryptoCurrencyRepository works with data from Tangem coins backend, CoinMarketCap etc
*/
interface MarketCryptoCurrencyRepository {
suspend fun isExchangeable(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID): Boolean
}

View file

@ -84,12 +84,12 @@ internal class TokenDetailsViewModel @Inject constructor(
private fun updateContent(selectedWallet: UserWallet) {
updateMarketPrice(selectedWallet = selectedWallet)
updateButtons(userWalletId = selectedWallet.walletId, currencyId = cryptoCurrency.id.value)
updateButtons(userWalletId = selectedWallet.walletId, currency = cryptoCurrency)
updateTxHistory()
}
private fun updateButtons(userWalletId: UserWalletId, currencyId: String) {
getCryptoCurrencyActionsUseCase(userWalletId = userWalletId, tokenId = currencyId)
private fun updateButtons(userWalletId: UserWalletId, currency: CryptoCurrency) {
getCryptoCurrencyActionsUseCase(userWalletId = userWalletId, cryptoCurrency = currency)
.distinctUntilChanged()
.onEach { uiState = stateFactory.getManageButtonsState(actions = it.states) }
.flowOn(dispatchers.io)

View file

@ -201,7 +201,6 @@ internal class WalletViewModel @Inject constructor(
private fun updateSingleCurrencyContent(index: Int, isRefreshing: Boolean) {
val wallet = getWallet(index)
val blockchain = getCardTypeResolver(index).getBlockchain()
updateButtons(userWalletId = wallet.walletId, currencyId = blockchain.id)
updateTxHistory(
blockchain = blockchain,
derivationStyle = wallet.scanResponse.derivationStyleProvider.getDerivationStyle(),
@ -244,15 +243,18 @@ internal class WalletViewModel @Inject constructor(
isRefreshing = isRefreshing,
)
either.onRight { status -> cryptoCurrencyStatus = status }
either.onRight { status ->
cryptoCurrencyStatus = status
updateButtons(userWalletId = userWalletId, currency = status.currency)
}
}
.flowOn(dispatchers.io)
.launchIn(viewModelScope)
.saveIn(marketPriceJobHolder)
}
private fun updateButtons(userWalletId: UserWalletId, currencyId: String) {
getCryptoCurrencyActionsUseCase(userWalletId = userWalletId, tokenId = currencyId)
private fun updateButtons(userWalletId: UserWalletId, currency: CryptoCurrency) {
getCryptoCurrencyActionsUseCase(userWalletId = userWalletId, cryptoCurrency = currency)
.distinctUntilChanged()
.onEach { uiState = stateFactory.getSingleCurrencyManageButtonsState(actions = it.states) }
.flowOn(dispatchers.io)