Updated on 2026-08-14

This commit is contained in:
Tangem 2023-09-21 20:15:54 +03:00
parent 613e07734e
commit 3fc34fac64
103 changed files with 403 additions and 297 deletions

View file

@ -0,0 +1,21 @@
package com.tangem.datasource.di
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.network.DefaultNetworksStatusesStore
import com.tangem.datasource.local.network.NetworksStatusesStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
internal object NetworksStatusesStoreModule {
@Provides
fun provideNetworksStatusesStore(): NetworksStatusesStore {
return DefaultNetworksStatusesStore(
dataStore = RuntimeDataStore(),
)
}
}

View file

@ -2,15 +2,10 @@ package com.tangem.datasource.local.cache
import com.tangem.datasource.local.cache.model.CacheKey
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
internal class DefaultCacheKeysStore(
dataStore: StringKeyDataStore<CacheKey>,
) : CacheKeysStore, StringKeyDataStoreDecorator<String, CacheKey>(dataStore) {
override fun provideStringKey(key: String): String {
return key
}
) : CacheKeysStore, StringKeyDataStore<CacheKey> by dataStore {
override suspend fun store(key: CacheKey) {
store(key.id, key)

View file

@ -4,7 +4,10 @@ import com.squareup.moshi.JsonAdapter
import com.tangem.datasource.files.FileReader
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.datastore.utils.Trigger
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import timber.log.Timber
@Deprecated("Use shared preferences data store instead")
@ -33,16 +36,16 @@ internal class FileDataStore<Value : Any>(
return getInternal(key)
}
override suspend fun getAllSyncOrNull(): List<Value> {
override suspend fun getAllSyncOrNull(): List<Value>? {
val e = NotImplementedError("`getAllSyncOrNull()` function not implemented for `FileDataStore`")
Timber.e(e)
throw e
}
override suspend fun store(key: String, item: Value) {
override suspend fun store(key: String, value: Value) {
try {
val json = adapter.toJson(item)
val json = adapter.toJson(value)
fileReader.rewriteFile(json, key)
writeTrigger.trigger()
@ -51,8 +54,8 @@ internal class FileDataStore<Value : Any>(
}
}
override suspend fun store(items: Map<String, Value>) {
items.forEach { (key, item) ->
override suspend fun store(values: Map<String, Value>) {
values.forEach { (key, item) ->
store(key, item)
}
}

View file

@ -5,37 +5,45 @@ import kotlinx.coroutines.flow.*
internal class RuntimeDataStore<Data : Any> : StringKeyDataStore<Data> {
private val store = MutableStateFlow<HashMap<String, Data>>(hashMapOf())
private val store: MutableSharedFlow<HashMap<String, Data>?> = MutableSharedFlow(replay = 1)
init {
store.tryEmit(value = null)
}
override fun get(key: String): Flow<Data> {
return store
.map { value -> value[key] }
.map { value ->
value?.get(key)
}
.filterNotNull()
}
override fun getAll(): Flow<List<Data>> {
return store.map { value -> value.values.toList() }
}
override suspend fun getSyncOrNull(key: String): Data? {
return store.value[key]
}
override suspend fun getAllSyncOrNull(): List<Data> {
return store.value.values.toList()
}
override suspend fun store(key: String, item: Data) {
store.update { value ->
value[key] = item
value
return store.map { value ->
value?.values?.toList().orEmpty()
}
}
override suspend fun store(items: Map<String, Data>) {
store.update { value ->
items.forEach { (key, item) ->
override suspend fun getSyncOrNull(key: String): Data? {
return store.firstOrNull()?.get(key)
}
override suspend fun getAllSyncOrNull(): List<Data>? {
return store.firstOrNull()?.values?.toList()
}
override suspend fun store(key: String, value: Data) {
updateValue { storedValue ->
storedValue[key] = value
storedValue
}
}
override suspend fun store(values: Map<String, Data>) {
updateValue { value ->
values.forEach { (key, item) ->
value[key] = item
}
@ -44,7 +52,7 @@ internal class RuntimeDataStore<Data : Any> : StringKeyDataStore<Data> {
}
override suspend fun remove(key: String) {
store.update { value ->
updateValue { value ->
value.remove(key)
value
@ -52,6 +60,13 @@ internal class RuntimeDataStore<Data : Any> : StringKeyDataStore<Data> {
}
override suspend fun clear() {
store.update { hashMapOf() }
store.emit(value = null)
}
private suspend inline fun updateValue(update: (HashMap<String, Data>) -> HashMap<String, Data>) {
val storedData = store.firstOrNull() ?: hashMapOf()
val updatedData = update(storedData)
store.emit(updatedData)
}
}

View file

@ -46,9 +46,9 @@ internal class SharedPreferencesDataStore<Value : Any>(
return getAllInternal()
}
override suspend fun store(key: String, item: Value) {
override suspend fun store(key: String, value: Value) {
try {
val json = adapter.toJson(item)
val json = adapter.toJson(value)
sharedPreferences.edit { putString(key, json) }
writeTrigger.trigger()
@ -57,8 +57,8 @@ internal class SharedPreferencesDataStore<Value : Any>(
}
}
override suspend fun store(items: Map<String, Value>) {
items.forEach { (key, item) ->
override suspend fun store(values: Map<String, Value>) {
values.forEach { (key, item) ->
store(key, item)
}
}

View file

@ -10,11 +10,11 @@ internal interface DataStore<Key : Any, Value : Any> {
suspend fun getSyncOrNull(key: Key): Value?
suspend fun getAllSyncOrNull(): List<Value>
suspend fun getAllSyncOrNull(): List<Value>?
suspend fun store(key: Key, item: Value)
suspend fun store(key: Key, value: Value)
suspend fun store(items: Map<Key, Value>)
suspend fun store(values: Map<Key, Value>)
suspend fun remove(key: Key)

View file

@ -16,7 +16,7 @@ internal abstract class StringKeyDataStoreDecorator<Key : Any, Value : Any>(
return wrappedDataStore.getAll()
}
override suspend fun getAllSyncOrNull(): List<Value> {
override suspend fun getAllSyncOrNull(): List<Value>? {
return wrappedDataStore.getAllSyncOrNull()
}
@ -24,13 +24,13 @@ internal abstract class StringKeyDataStoreDecorator<Key : Any, Value : Any>(
return wrappedDataStore.getSyncOrNull(provideStringKey(key))
}
override suspend fun store(key: Key, item: Value) {
wrappedDataStore.store(provideStringKey(key), item)
override suspend fun store(key: Key, value: Value) {
wrappedDataStore.store(provideStringKey(key), value)
}
override suspend fun store(items: Map<Key, Value>) {
override suspend fun store(values: Map<Key, Value>) {
wrappedDataStore.store(
items = items.mapKeys { (key, _) -> provideStringKey(key) },
values = values.mapKeys { (key, _) -> provideStringKey(key) },
)
}

View file

@ -0,0 +1,24 @@
package com.tangem.datasource.local.network
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.extensions.addOrReplace
internal class DefaultNetworksStatusesStore(
dataStore: StringKeyDataStore<Set<NetworkStatus>>,
) : NetworksStatusesStore, StringKeyDataStoreDecorator<UserWalletId, Set<NetworkStatus>>(dataStore) {
override fun provideStringKey(key: UserWalletId): String {
return key.stringValue
}
override suspend fun store(key: UserWalletId, value: NetworkStatus) {
val newValues = getSyncOrNull(key)
?.addOrReplace(value) { it.network == value.network }
?: setOf(value)
store(key, newValues)
}
}

View file

@ -0,0 +1,14 @@
package com.tangem.datasource.local.network
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.Flow
interface NetworksStatusesStore {
fun get(key: UserWalletId): Flow<Set<NetworkStatus>>
suspend fun getSyncOrNull(key: UserWalletId): Set<NetworkStatus>?
suspend fun store(key: UserWalletId, value: NetworkStatus)
}

View file

@ -3,7 +3,7 @@ package com.tangem.datasource.local.quote
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.quote.model.StoredQuote
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrency
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine

View file

@ -2,7 +2,7 @@ package com.tangem.datasource.local.quote
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
import com.tangem.datasource.local.quote.model.StoredQuote
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrency
import kotlinx.coroutines.flow.Flow
interface QuotesStore {

View file

@ -10,5 +10,5 @@ interface UserTokensStore {
suspend fun getSyncOrNull(key: UserWalletId): UserTokensResponse?
suspend fun store(key: UserWalletId, item: UserTokensResponse)
suspend fun store(key: UserWalletId, value: UserTokensResponse)
}