Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-02 17:54:38 +05:00
parent 28d15c9043
commit a4eb7fce06
6 changed files with 41 additions and 38 deletions

View file

@ -124,7 +124,7 @@ internal class MainViewModel @Inject constructor(
private fun fetchStakingTokens() {
viewModelScope.launch(dispatchers.main) {
fetchStakingTokensUseCase(true)
fetchStakingTokensUseCase()
.onLeft { Timber.e(it.toString(), "Unable to fetch the staking tokens list") }
.onRight { Timber.d("Staking token list was fetched successfully") }
}

View file

@ -5,10 +5,12 @@ import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import com.squareup.moshi.Moshi
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.datastore.RuntimeSharedStore
import com.tangem.datasource.local.token.*
import com.tangem.datasource.utils.MoshiDataStoreSerializer
import com.tangem.datasource.utils.listTypes
import com.tangem.datasource.utils.mapWithStringKeyTypes
import com.tangem.datasource.utils.setTypes
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -27,8 +29,22 @@ internal object StakingStoreModule {
@Provides
@Singleton
fun provideStakingTokensStore(): StakingYieldsStore {
return DefaultStakingYieldsStore(dataStore = RuntimeDataStore())
fun provideStakingTokensStore(
@NetworkMoshi moshi: Moshi,
@ApplicationContext context: Context,
dispatchers: CoroutineDispatcherProvider,
): StakingYieldsStore {
return DefaultStakingYieldsStore(
dataStore = DataStoreFactory.create(
serializer = MoshiDataStoreSerializer(
moshi = moshi,
types = listTypes<YieldDTO>(),
defaultValue = emptyList(),
),
produceFile = { context.dataStoreFile(fileName = "yields_cache") },
scope = CoroutineScope(context = dispatchers.io + SupervisorJob()),
),
)
}
@Provides

View file

@ -1,32 +1,25 @@
package com.tangem.datasource.local.token
import androidx.datastore.core.DataStore
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.flow.firstOrNull
internal class DefaultStakingYieldsStore(
private val dataStore: StringKeyDataStore<List<YieldDTO>>,
private val dataStore: DataStore<List<YieldDTO>>,
) : StakingYieldsStore {
private val mutex = Mutex()
override fun get(): Flow<List<YieldDTO>> {
return dataStore.get(KEY)
return dataStore.data
}
override suspend fun getSync(): List<YieldDTO> {
return dataStore.getSyncOrNull(KEY) ?: emptyList()
return dataStore.data.firstOrNull().orEmpty()
}
override suspend fun store(items: List<YieldDTO>) {
mutex.withLock {
dataStore.store(KEY, items)
dataStore.updateData { _ ->
items
}
}
companion object {
private const val KEY = "DefaultStakingYieldsStore"
}
}

View file

@ -108,25 +108,19 @@ internal class DefaultStakingRepository(
return integrationIdMap.getOrDefault(getIntegrationKey(cryptoCurrencyId), null)
}
override suspend fun fetchEnabledYields(refresh: Boolean) {
override suspend fun fetchEnabledYields() {
withContext(dispatchers.io) {
cacheRegistry.invokeOnExpire(
key = YIELDS_STORE_KEY,
skipCache = refresh,
block = {
when (val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = false)) {
is ApiResponse.Success -> stakingYieldsStore.store(
stakingTokensWithYields.data.data.filter {
it.isAvailable ?: false
},
)
else -> {
stakingYieldsStore.store(emptyList())
throw (stakingTokensWithYields as ApiResponse.Error).cause
}
}
},
)
when (val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = false)) {
is ApiResponse.Success -> stakingYieldsStore.store(
stakingTokensWithYields.data.data.filter {
it.isAvailable ?: false
},
)
else -> {
stakingYieldsStore.store(emptyList())
throw (stakingTokensWithYields as ApiResponse.Error).cause
}
}
}
}

View file

@ -14,10 +14,10 @@ class FetchStakingTokensUseCase(
private val stakingRepository: StakingRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(isRefresh: Boolean = false): Either<StakingError, Unit> {
suspend operator fun invoke(): Either<StakingError, Unit> {
return either {
catch(
block = { stakingRepository.fetchEnabledYields(isRefresh) },
block = { stakingRepository.fetchEnabledYields() },
catch = { stakingErrorResolver.resolve(it) },
)
}

View file

@ -27,7 +27,7 @@ interface StakingRepository {
fun getSupportedIntegrationId(cryptoCurrencyId: CryptoCurrency.ID): String?
suspend fun fetchEnabledYields(refresh: Boolean)
suspend fun fetchEnabledYields()
suspend fun getEntryInfo(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingEntryInfo