Updated on 2026-08-14
This commit is contained in:
parent
a8f084ae88
commit
4d5b9b87e6
12 changed files with 105 additions and 17 deletions
|
|
@ -39,5 +39,13 @@ internal class DefaultUserTokensResponseStore(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun clear(userWalletId: UserWalletId) {
|
||||
appPreferencesStore.updateData { preferences ->
|
||||
val key = createPreferencesKey(userWalletId = userWalletId.stringValue)
|
||||
|
||||
preferences.toMutablePreferences().apply { remove(key) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPreferencesKey(userWalletId: String) = stringPreferencesKey(name = "user_tokens_$userWalletId")
|
||||
}
|
||||
|
|
@ -17,4 +17,6 @@ interface UserTokensResponseStore {
|
|||
suspend fun getSyncOrNull(userWalletId: UserWalletId): UserTokensResponse?
|
||||
|
||||
suspend fun store(userWalletId: UserWalletId, response: UserTokensResponse)
|
||||
|
||||
suspend fun clear(userWalletId: UserWalletId)
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import dagger.assisted.AssistedInject
|
|||
*/
|
||||
internal class GetWalletAccountsResponseConverter @AssistedInject constructor(
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted val version: Int,
|
||||
cryptoPortfolioConverterFactory: CryptoPortfolioConverter.Factory,
|
||||
) : Converter<AccountList, GetWalletAccountsResponse> {
|
||||
|
||||
|
|
@ -25,7 +24,6 @@ internal class GetWalletAccountsResponseConverter @AssistedInject constructor(
|
|||
override fun convert(value: AccountList): GetWalletAccountsResponse {
|
||||
return GetWalletAccountsResponse(
|
||||
wallet = GetWalletAccountsResponse.Wallet(
|
||||
version = version,
|
||||
group = TokensGroupTypeConverter.convertBack(value.groupType),
|
||||
sort = TokensSortTypeConverter.convertBack(value.sortType),
|
||||
totalAccounts = value.totalAccounts,
|
||||
|
|
@ -39,6 +37,6 @@ internal class GetWalletAccountsResponseConverter @AssistedInject constructor(
|
|||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(userWallet: UserWallet, version: Int): GetWalletAccountsResponseConverter
|
||||
fun create(userWallet: UserWallet): GetWalletAccountsResponseConverter
|
||||
}
|
||||
}
|
||||
|
|
@ -104,9 +104,10 @@ internal class FetchWalletAccountsErrorHandler @Inject constructor(
|
|||
): UserTokensResponse? {
|
||||
if (this != null) return this
|
||||
|
||||
return userTokensResponseStore.getSyncOrNull(
|
||||
userWalletId = userWalletProvider().walletId,
|
||||
)
|
||||
val userWalletId = userWalletProvider().walletId
|
||||
|
||||
return userTokensResponseStore.getSyncOrNull(userWalletId)
|
||||
.also { userTokensResponseStore.clear(userWalletId) }
|
||||
}
|
||||
|
||||
private fun UserTokensResponse?.orDefault(userWalletProvider: Provider<UserWallet>): UserTokensResponse {
|
||||
|
|
|
|||
|
|
@ -112,10 +112,7 @@ internal class DefaultAccountsCRUDRepository(
|
|||
.getOrThrow()
|
||||
}
|
||||
|
||||
val converter = convertersContainer.getWalletAccountsResponseCF.create(
|
||||
userWallet = accountList.userWallet,
|
||||
version = version,
|
||||
)
|
||||
val converter = convertersContainer.getWalletAccountsResponseCF.create(userWallet = accountList.userWallet)
|
||||
|
||||
val accountsResponse = converter.convert(value = accountList)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ class GetWalletAccountsResponseConverterTest {
|
|||
private val cryptoPortfolioConverter = mockk<CryptoPortfolioConverter>()
|
||||
private val converter = GetWalletAccountsResponseConverter(
|
||||
userWallet = userWallet,
|
||||
version = 0,
|
||||
cryptoPortfolioConverterFactory = cryptoPortfolioConverterFactory,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class FetchWalletAccountsErrorHandlerTest {
|
|||
|
||||
private val userTokensSaver: UserTokensSaver = mockk(relaxUnitFun = true)
|
||||
private val userWalletsStore: UserWalletsStore = mockk()
|
||||
private val userTokensResponseStore: UserTokensResponseStore = mockk()
|
||||
private val userTokensResponseStore: UserTokensResponseStore = mockk(relaxUnitFun = true)
|
||||
private val cryptoPortfolioCF: CryptoPortfolioConverter.Factory = mockk()
|
||||
private val cryptoPortfolioConverter = mockk<CryptoPortfolioConverter>()
|
||||
private val userTokensResponseFactory: UserTokensResponseFactory = mockk()
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ class DefaultAccountsCRUDRepositoryTest {
|
|||
}
|
||||
|
||||
every {
|
||||
convertersContainer.getWalletAccountsResponseCF.create(userWallet = userWallet, version = version)
|
||||
convertersContainer.getWalletAccountsResponseCF.create(userWallet = userWallet)
|
||||
} returns converter
|
||||
|
||||
coEvery { accountsResponseStore.updateData(transform = any()) } returns accountsResponse
|
||||
|
|
@ -610,7 +610,7 @@ class DefaultAccountsCRUDRepositoryTest {
|
|||
accountsResponseStoreFactory.create(userWalletId)
|
||||
accountsResponseStore.data
|
||||
tangemTechApi.saveWalletAccounts(userWalletId.stringValue, version.toString(), body)
|
||||
convertersContainer.getWalletAccountsResponseCF.create(userWallet, version)
|
||||
convertersContainer.getWalletAccountsResponseCF.create(userWallet)
|
||||
converter.convert(accountList)
|
||||
accountsResponseStore.updateData(any())
|
||||
}
|
||||
|
|
@ -656,7 +656,7 @@ class DefaultAccountsCRUDRepositoryTest {
|
|||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
convertersContainer.getWalletAccountsResponseCF.create(any(), any())
|
||||
convertersContainer.getWalletAccountsResponseCF.create(any())
|
||||
accountsResponseStore.updateData(any())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
data/common/src/main/kotlin/com/tangem/data/common/cache/etag/DefaultETagsStore.kt
vendored
Normal file
40
data/common/src/main/kotlin/com/tangem/data/common/cache/etag/DefaultETagsStore.kt
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.data.common.cache.etag
|
||||
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrNull
|
||||
import com.tangem.datasource.local.preferences.utils.store
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Default implementation of the [ETagsStore] interface for managing ETag values
|
||||
*
|
||||
* @property appPreferencesStore the preferences store used for saving and retrieving ETag values
|
||||
*/
|
||||
internal class DefaultETagsStore(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
) : ETagsStore {
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, key: ETagsStore.Key): String? {
|
||||
val key = getAccountsETagKey(userWalletId = userWalletId, key = key)
|
||||
|
||||
return appPreferencesStore.getSyncOrNull(key = key)
|
||||
}
|
||||
|
||||
override suspend fun store(userWalletId: UserWalletId, key: ETagsStore.Key, value: String) {
|
||||
if (value.isBlank()) {
|
||||
Timber.e("ETag value is blank, not storing it. userWalletId: $userWalletId, key: $key")
|
||||
return
|
||||
}
|
||||
|
||||
val key = getAccountsETagKey(userWalletId = userWalletId, key = key)
|
||||
|
||||
appPreferencesStore.store(key = key, value = value)
|
||||
}
|
||||
|
||||
private fun getAccountsETagKey(userWalletId: UserWalletId, key: ETagsStore.Key): Preferences.Key<String> {
|
||||
return stringPreferencesKey(name = "etag_${key}_${userWalletId.stringValue}")
|
||||
}
|
||||
}
|
||||
34
data/common/src/main/kotlin/com/tangem/data/common/cache/etag/ETagsStore.kt
vendored
Normal file
34
data/common/src/main/kotlin/com/tangem/data/common/cache/etag/ETagsStore.kt
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.data.common.cache.etag
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
/**
|
||||
* Interface for working with ETag (Entity Tag), which is used for data caching and validation.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface ETagsStore {
|
||||
|
||||
/**
|
||||
* Retrieves the stored ETag value for the specified wallet and key
|
||||
*
|
||||
* @param userWalletId identifier of the user wallet
|
||||
* @param key the key for which to get the ETag value
|
||||
*/
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, key: Key): String?
|
||||
|
||||
/**
|
||||
* Stores the ETag value for the specified wallet and key
|
||||
*
|
||||
* @param userWalletId identifier of the user wallet
|
||||
* @param key the key for which to get the ETag value
|
||||
*/
|
||||
suspend fun store(userWalletId: UserWalletId, key: Key, value: String)
|
||||
|
||||
/** Enumeration of possible keys for storing ETag values */
|
||||
enum class Key {
|
||||
WalletAccounts,
|
||||
UserTokens,
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -50,9 +50,9 @@ object UserTokensResponseAccountIdEnricher {
|
|||
|
||||
if (enrichedTokens.isEmpty()) return tokens
|
||||
|
||||
val enrichedTokenMap = enrichedTokens.associateBy { it }
|
||||
return tokens.map { token ->
|
||||
val enrichedToken = enrichedTokens.firstOrNull { it == token }
|
||||
enrichedToken ?: token
|
||||
enrichedTokenMap[token] ?: token
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package com.tangem.data.common.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.common.cache.etag.DefaultETagsStore
|
||||
import com.tangem.data.common.cache.etag.ETagsStore
|
||||
import com.tangem.data.common.currency.*
|
||||
import com.tangem.data.common.quote.DefaultQuotesFetcher
|
||||
import com.tangem.data.common.quote.QuotesFetcher
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
|
|
@ -76,4 +79,10 @@ internal object DataCommonModule {
|
|||
fun provideQuotesFetcher(tangemTechApi: TangemTechApi, dispatchers: CoroutineDispatcherProvider): QuotesFetcher {
|
||||
return DefaultQuotesFetcher(tangemTechApi = tangemTechApi, dispatchers = dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideETagsStore(appPreferencesStore: AppPreferencesStore): ETagsStore {
|
||||
return DefaultETagsStore(appPreferencesStore = appPreferencesStore)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue