Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-09 12:10:19 +03:00
parent 8670d180d1
commit 03019b0c4c
12 changed files with 50 additions and 68 deletions

View file

@ -1,6 +1,5 @@
package com.tangem.datasource.di
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.token.DefaultStakingYieldsStore
import com.tangem.datasource.local.token.StakingYieldsStore
import dagger.Module
@ -16,6 +15,6 @@ internal object StakingTokensStoreModule {
@Provides
@Singleton
fun provideStakingTokensStore(): StakingYieldsStore {
return DefaultStakingYieldsStore(dataStore = RuntimeDataStore())
return DefaultStakingYieldsStore()
}
}

View file

@ -1,21 +0,0 @@
package com.tangem.datasource.local.token
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.domain.staking.model.StakingTokenWithYield
internal class DefaultStakingTokensStore(
private val dataStore: StringKeyDataStore<List<StakingTokenWithYield>>,
) : StakingTokensStore {
override suspend fun getSyncOrNull(): List<StakingTokenWithYield>? {
return dataStore.getSyncOrNull(STAKING_TOKENS_KEY)
}
override suspend fun store(items: List<StakingTokenWithYield>) {
dataStore.store(STAKING_TOKENS_KEY, items)
}
companion object {
private const val STAKING_TOKENS_KEY = "STAKING_TOKENS_KEY"
}
}

View file

@ -1,21 +1,16 @@
package com.tangem.datasource.local.token
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
internal class DefaultStakingYieldsStore(
private val dataStore: StringKeyDataStore<List<YieldDTO>>,
) : StakingYieldsStore {
internal class DefaultStakingYieldsStore : StakingYieldsStore {
override suspend fun getSyncOrNull(): List<YieldDTO>? {
return dataStore.getSyncOrNull(STAKING_YIELDS_KEY)
private var yields = mutableListOf<YieldDTO>()
override fun get(): List<YieldDTO> {
return yields
}
override suspend fun store(items: List<YieldDTO>) {
dataStore.store(STAKING_YIELDS_KEY, items)
}
companion object {
private const val STAKING_YIELDS_KEY = "STAKING_YIELDS_KEY"
override fun store(items: List<YieldDTO>) {
yields = items.toMutableList()
}
}

View file

@ -4,7 +4,7 @@ import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
interface StakingYieldsStore {
suspend fun getSyncOrNull(): List<YieldDTO>?
fun get(): List<YieldDTO>
suspend fun store(items: List<YieldDTO>)
fun store(items: List<YieldDTO>)
}

View file

@ -133,11 +133,10 @@ internal class DefaultStakingRepository(
override suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield {
return withContext(dispatchers.io) {
val yields = getEnabledYields() ?: error("No yields found")
val rawCurrencyId = cryptoCurrencyId.rawCurrencyId ?: error("Staking custom tokens is not available")
val prefetchedYield = findPrefetchedYield(
yields = yields,
yields = getEnabledYields(),
currencyId = rawCurrencyId,
symbol = symbol,
)
@ -158,7 +157,7 @@ internal class DefaultStakingRepository(
}
}
override suspend fun getStakingAvailability(
override fun getStakingAvailability(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): StakingAvailability {
@ -166,26 +165,22 @@ internal class DefaultStakingRepository(
val rawCurrencyId = cryptoCurrency.id.rawCurrencyId ?: return StakingAvailability.Unavailable
return withContext(dispatchers.io) {
val isSupportedInMobileApp = getSupportedIntegrationId(cryptoCurrency.id).isNullOrEmpty().not()
val isSupportedInMobileApp = getSupportedIntegrationId(cryptoCurrency.id).isNullOrEmpty().not()
val yields = getEnabledYields() ?: return@withContext if (isSupportedInMobileApp) {
val prefetchedYield = findPrefetchedYield(
yields = getEnabledYields(),
currencyId = rawCurrencyId,
symbol = cryptoCurrency.symbol,
)
return when {
prefetchedYield != null && isSupportedInMobileApp -> {
StakingAvailability.Available(prefetchedYield.id)
}
prefetchedYield == null && isSupportedInMobileApp -> {
StakingAvailability.TemporaryUnavailable
} else {
StakingAvailability.Unavailable
}
val prefetchedYield = findPrefetchedYield(yields, rawCurrencyId, cryptoCurrency.symbol)
when {
prefetchedYield != null && isSupportedInMobileApp -> {
StakingAvailability.Available(prefetchedYield.id)
}
prefetchedYield == null && isSupportedInMobileApp -> {
StakingAvailability.TemporaryUnavailable
}
else -> StakingAvailability.Unavailable
}
else -> StakingAvailability.Unavailable
}
}
@ -398,7 +393,7 @@ internal class DefaultStakingRepository(
key = getYieldBalancesKey(userWalletId),
skipCache = refresh,
block = {
val yields = getEnabledYields() ?: error("No yields found")
val yields = getEnabledYields()
val availableCurrencies = cryptoCurrencies
.mapNotNull { currency ->
val addresses = walletManagersFacade.getAddresses(userWalletId, currency.network)
@ -583,9 +578,10 @@ internal class DefaultStakingRepository(
}
}
private suspend fun getEnabledYields(): List<Yield>? {
val yields = stakingYieldsStore.getSyncOrNull() ?: return null
return yields.map { yieldConverter.convert(it) }
private fun getEnabledYields(): List<Yield> {
return stakingYieldsStore
.get()
.map { yieldConverter.convert(it) }
}
private fun getBalanceRequestData(address: String, integrationId: String): YieldBalanceRequestBody {

View file

@ -16,7 +16,7 @@ class GetStakingAvailabilityUseCase(
private val stakingErrorResolver: StakingErrorResolver,
) {
suspend operator fun invoke(
operator fun invoke(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): Either<StakingError, StakingAvailability> {

View file

@ -32,7 +32,7 @@ interface StakingRepository {
suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield
suspend fun getStakingAvailability(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): StakingAvailability
fun getStakingAvailability(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): StakingAvailability
suspend fun fetchSingleYieldBalance(
userWalletId: UserWalletId,

View file

@ -113,7 +113,7 @@ class MockStakingRepository : StakingRepository {
isAvailable = false,
)
override suspend fun getStakingAvailability(
override fun getStakingAvailability(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): StakingAvailability = StakingAvailability.Unavailable

View file

@ -65,7 +65,7 @@ internal class TokenDetailsFragment : ComposeFragment() {
val cryptoCurrency: CryptoCurrency = arguments
?.getBundle(AppRoute.CurrencyDetails.CRYPTO_CURRENCY_KEY)
?.unbundle(CryptoCurrency.serializer())
?: error("Token Details screen can't open without `CryptoCurrency`")
?: error("Token Details screen can't be opened without `CryptoCurrency`")
val param = cryptoCurrency.toParam() ?: return

View file

@ -10,7 +10,9 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.card.NetworkHasDerivationUseCase
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
import com.tangem.domain.staking.GetStakingIntegrationIdUseCase
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWalletId
@ -30,6 +32,7 @@ internal class TokenDetailsSkeletonStateConverter(
private val clickIntents: TokenDetailsClickIntents,
private val networkHasDerivationUseCase: NetworkHasDerivationUseCase,
private val getStakingIntegrationIdUseCase: GetStakingIntegrationIdUseCase,
private val getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase,
private val userWalletId: UserWalletId,
) : Converter<CryptoCurrency, TokenDetailsState> {
@ -39,6 +42,8 @@ internal class TokenDetailsSkeletonStateConverter(
override fun convert(value: CryptoCurrency): TokenDetailsState {
val iconState = iconStateConverter.convert(value)
val isSupportedInMobileApp = getStakingIntegrationIdUseCase(value.id).isNullOrBlank().not()
val stakingAvailability = getStakingAvailabilityUseCase(userWalletId, value)
.getOrElse { StakingAvailability.Unavailable }
return TokenDetailsState(
topAppBarConfig = TokenDetailsTopAppBarConfig(
@ -63,7 +68,11 @@ internal class TokenDetailsSkeletonStateConverter(
selectedBalanceType = BalanceType.ALL,
),
marketPriceBlockState = MarketPriceBlockState.Loading(value.symbol),
stakingBlocksState = StakingBlockUM.Loading(iconState).takeIf { isSupportedInMobileApp },
stakingBlocksState = if (stakingAvailability == StakingAvailability.TemporaryUnavailable) {
StakingBlockUM.TemporaryUnavailable
} else {
StakingBlockUM.Loading(iconState).takeIf { isSupportedInMobileApp }
},
notifications = persistentListOf(),
pendingTxs = persistentListOf(),
swapTxs = persistentListOf(),

View file

@ -17,6 +17,7 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.card.NetworkHasDerivationUseCase
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
import com.tangem.domain.staking.GetStakingIntegrationIdUseCase
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
@ -60,6 +61,7 @@ internal class TokenDetailsStateFactory(
private val userWalletId: UserWalletId,
stakingFeatureToggles: StakingFeatureToggles,
getStakingIntegrationIdUseCase: GetStakingIntegrationIdUseCase,
getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase,
symbol: String,
decimals: Int,
) {
@ -69,6 +71,7 @@ internal class TokenDetailsStateFactory(
clickIntents = clickIntents,
networkHasDerivationUseCase = networkHasDerivationUseCase,
getStakingIntegrationIdUseCase = getStakingIntegrationIdUseCase,
getStakingAvailabilityUseCase = getStakingAvailabilityUseCase,
getUserWalletUseCase = getUserWalletUseCase,
userWalletId = userWalletId,
)

View file

@ -135,12 +135,12 @@ internal class TokenDetailsViewModel @Inject constructor(
private val userWalletId: UserWalletId = savedStateHandle.get<Bundle>(AppRoute.CurrencyDetails.USER_WALLET_ID_KEY)
?.unbundle(UserWalletId.serializer())
?: error("This screen can't open without `UserWalletId`")
?: error("This screen can't be opened without `UserWalletId`")
private val cryptoCurrency: CryptoCurrency =
savedStateHandle.get<Bundle>(AppRoute.CurrencyDetails.CRYPTO_CURRENCY_KEY)
?.unbundle(CryptoCurrency.serializer())
?: error("This screen can't open without `CryptoCurrency`")
?: error("This screen can't be opened without `CryptoCurrency`")
private val userWallet: UserWallet
@ -172,6 +172,7 @@ internal class TokenDetailsViewModel @Inject constructor(
userWalletId = userWalletId,
stakingFeatureToggles = stakingFeatureToggles,
getStakingIntegrationIdUseCase = getStakingIntegrationIdUseCase,
getStakingAvailabilityUseCase = getStakingAvailabilityUseCase,
symbol = cryptoCurrency.symbol,
decimals = cryptoCurrency.decimals,
)