Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-05 14:10:57 +01:00
parent ea8ed2812d
commit c68766a676
7 changed files with 98 additions and 7 deletions

View file

@ -370,4 +370,16 @@ internal object TokensDomainModule {
networksRepository = networksRepository,
)
}
@Provides
@Singleton
fun provideRefreshMultiCurrencyWalletQuotesUseCase(
currenciesRepository: CurrenciesRepository,
quotesRepository: QuotesRepository,
): RefreshMultiCurrencyWalletQuotesUseCase {
return RefreshMultiCurrencyWalletQuotesUseCase(
currenciesRepository = currenciesRepository,
quotesRepository = quotesRepository,
)
}
}

View file

@ -51,6 +51,19 @@ internal class DefaultQuotesRepository(
.flowOn(dispatchers.io)
}
override suspend fun fetchQuotes(currenciesIds: Set<CryptoCurrency.ID>) {
withContext(dispatchers.io) {
val selectedAppCurrency = requireNotNull(
value = appPreferencesStore.getObjectSyncOrNull<CurrenciesResponse.Currency>(
key = PreferencesKeys.SELECTED_APP_CURRENCY_KEY,
),
lazyMessage = { "Unable to get selected application currency to update quotes" },
)
fetchExpiredQuotes(currenciesIds, selectedAppCurrency.id, true)
}
}
override suspend fun getQuotesSync(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Set<Quote> {
return withContext(dispatchers.io) {
val selectedAppCurrency = requireNotNull(

View file

@ -0,0 +1,53 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.domain.tokens.error.QuotesError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
class RefreshMultiCurrencyWalletQuotesUseCase(
private val quotesRepository: QuotesRepository,
private val currenciesRepository: CurrenciesRepository,
) {
suspend operator fun invoke(userWalletId: UserWalletId): Either<QuotesError, Unit> {
return either {
val currencies = fetchCurrencies(userWalletId = userWalletId)
.getOrElse { raise(QuotesError.DataError(it)) }
coroutineScope {
val fetchQuotes = async {
fetchQuotes(
currenciesIds = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::id),
)
}
awaitAll(fetchQuotes)
}
}
}
private suspend fun fetchCurrencies(userWalletId: UserWalletId): Either<Throwable, List<CryptoCurrency>> {
return either {
catch(
block = { currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId, false) },
catch = { raise(it) },
)
}
}
private suspend fun fetchQuotes(currenciesIds: Set<CryptoCurrency.ID>) {
catch(
block = { quotesRepository.fetchQuotes(currenciesIds) },
catch = { /* Ignore error */ },
)
}
}

View file

@ -0,0 +1,5 @@
package com.tangem.domain.tokens.error
sealed class QuotesError {
data class DataError(val cause: Throwable) : QuotesError()
}

View file

@ -31,4 +31,6 @@ interface QuotesRepository {
suspend fun getQuotesSync(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Set<Quote>
suspend fun getQuoteSync(currencyId: CryptoCurrency.ID): Quote?
suspend fun fetchQuotes(currenciesIds: Set<CryptoCurrency.ID>)
}

View file

@ -25,4 +25,6 @@ internal class MockQuotesRepository(
return quotes.map { it.getOrElse { e -> throw e } }.first()
.first { it.rawCurrencyId == currencyId.rawCurrencyId }
}
override suspend fun fetchQuotes(currenciesIds: Set<CryptoCurrency.ID>) {}
}

View file

@ -4,11 +4,13 @@ import androidx.compose.runtime.MutableState
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import arrow.core.getOrElse
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.settings.CanUseBiometryUseCase
import com.tangem.domain.settings.IsWalletsScrollPreviewEnabled
import com.tangem.domain.settings.ShouldShowSaveWalletScreenUseCase
import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
@ -21,7 +23,6 @@ import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContent
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent.DemonstrateWalletsScrollPreview.Direction
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletPullToRefreshConfig
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state.transformers.*
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
@ -61,6 +62,7 @@ internal class WalletViewModel @Inject constructor(
private val selectedWalletAnalyticsSender: SelectedWalletAnalyticsSender,
private val walletDeepLinksHandler: WalletDeepLinksHandler,
private val walletNameMigrationUseCase: WalletNameMigrationUseCase,
private val refreshMultiCurrencyWalletQuotesUseCase: RefreshMultiCurrencyWalletQuotesUseCase,
) : ViewModel() {
val uiState: StateFlow<WalletScreenState> = stateHolder.uiState
@ -178,7 +180,7 @@ internal class WalletViewModel @Inject constructor(
}
}
// We need to update the current wallet if the application was in the background for more than 10 seconds
// We need to update the current wallet quotes if the application was in the background for more than 10 seconds
// and then returned to the foreground
private fun subscribeToScreenBackgroundState() {
screenLifecycleProvider.isBackgroundState
@ -186,7 +188,7 @@ internal class WalletViewModel @Inject constructor(
refreshWalletJobHolder.cancel()
when {
isBackground -> needToRefreshTimer()
needToRefreshWallet && !isBackground -> triggerRefreshWallet()
needToRefreshWallet && !isBackground -> triggerRefreshWalletQuotes()
}
}
.launchIn(viewModelScope)
@ -199,13 +201,15 @@ internal class WalletViewModel @Inject constructor(
}.saveIn(refreshWalletJobHolder)
}
private fun triggerRefreshWallet() {
private fun triggerRefreshWalletQuotes() {
needToRefreshWallet = false
val state = stateHolder.uiState.value
val wallet = state.wallets.getOrNull(state.selectedWalletIndex) ?: return
wallet.pullToRefreshConfig.onRefresh.invoke(
WalletPullToRefreshConfig.ShowRefreshState(false),
)
viewModelScope.launch {
refreshMultiCurrencyWalletQuotesUseCase(wallet.walletCardState.id).getOrElse {
Timber.e("Failed to refreshMultiCurrencyWalletQuotesUseCase $it")
}
}.saveIn(refreshWalletJobHolder)
}
private suspend fun updateWallets(action: WalletsUpdateActionResolver.Action) {