Updated on 2026-08-14

This commit is contained in:
Tangem 2023-07-24 11:41:13 +03:00
parent fcdfe622f9
commit effaf2d680
12 changed files with 157 additions and 13 deletions

View file

@ -79,8 +79,8 @@ class UserTokensRepository(
private fun List<Currency>.toUserTokensResponse(): UserTokensResponse {
return UserTokensResponse(
tokens = CurrencyConverter.convertList(input = this),
group = GROUP_DEFAULT_VALUE,
sort = SORT_DEFAULT_VALUE,
group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL,
)
}
@ -121,8 +121,6 @@ class UserTokensRepository(
private fun getUserWalletId(card: CardDTO): String? = UserWalletIdBuilder.card(card).build()?.stringValue
companion object {
private const val GROUP_DEFAULT_VALUE = "none"
private const val SORT_DEFAULT_VALUE = "manual"
private const val NOT_FOUND_HTTP_CODE = "404"
// TODO("After adding DI") get dependencies by DI

View file

@ -7,6 +7,7 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.files.FileReader
import com.tangem.tap.features.wallet.models.Currency
@Deprecated("Use [com.tangem.datasource.local.token.UserTokensStore] instead.")
class UserTokensStorageService(private val fileReader: FileReader) {
private val userTokensAdapter: JsonAdapter<UserTokensResponse> =
MoshiConverter.networkMoshi.adapter(UserTokensResponse::class.java)

View file

@ -9,8 +9,9 @@ plugins {
dependencies {
/** Project */
implementation(project(":core:utils"))
implementation(project(":libs:auth"))
implementation(projects.core.utils)
implementation(projects.libs.auth)
implementation(projects.domain.core)
/** Tangem libraries */
implementation(deps.tangem.blockchain)

View file

@ -4,8 +4,8 @@ import com.squareup.moshi.Json
data class UserTokensResponse(
@Json(name = "version") val version: Int = 0,
@Json(name = "group") val group: String? = null,
@Json(name = "sort") val sort: String? = null,
@Json(name = "group") val group: GroupType,
@Json(name = "sort") val sort: SortType,
@Json(name = "tokens") val tokens: List<Token> = emptyList(),
) {
@ -18,4 +18,26 @@ data class UserTokensResponse(
@Json(name = "decimals") val decimals: Int,
@Json(name = "contractAddress") val contractAddress: String?,
)
enum class GroupType {
@Json(name = "none")
NONE,
@Json(name = "token")
TOKEN,
@Json(name = "network")
NETWORK,
}
enum class SortType {
@Json(name = "balance")
BALANCE,
@Json(name = "manual")
MANUAL,
@Json(name = "marketcap")
MARKETCAP,
}
}

View file

@ -19,8 +19,8 @@ class MoshiModule {
@NetworkMoshi
fun provideNetworkMoshi(): Moshi {
return Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(BigDecimalAdapter())
.add(KotlinJsonAdapterFactory())
.build()
}

View file

@ -0,0 +1,22 @@
package com.tangem.datasource.di
import com.squareup.moshi.Moshi
import com.tangem.datasource.files.FileReader
import com.tangem.datasource.local.token.FileUserTokensStore
import com.tangem.datasource.local.token.UserTokensStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object UserTokensStoreModule {
@Provides
@Singleton
fun provideUserTokensStore(fileReader: FileReader, @NetworkMoshi moshi: Moshi): UserTokensStore {
return FileUserTokensStore(fileReader, moshi)
}
}

View file

@ -1,11 +1,11 @@
package com.tangem.datasource.local.cache
import com.tangem.datasource.local.cache.model.CacheKey
import com.tangem.datasource.local.store.RuntimeStore
import com.tangem.datasource.local.datastore.RuntimeDataStore
internal class RuntimeCacheKeysStore : CacheKeysStore {
private val store = RuntimeStore(keyProvider = CacheKey::id)
private val store = RuntimeDataStore(keyProvider = CacheKey::id)
override fun get(id: String): CacheKey? {
return store.getSync { it.id == id }.firstOrNull()

View file

@ -0,0 +1,52 @@
package com.tangem.datasource.local.datastore
import com.squareup.moshi.JsonAdapter
import com.tangem.datasource.files.FileReader
import com.tangem.domain.core.error.DataError
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
internal class FileDataStore<Data>(
private val fileNameProvider: (key: String) -> String,
private val fileReader: FileReader,
private val adapter: JsonAdapter<Data>,
) {
private val writeTrigger = MutableSharedFlow<Unit>(
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
fun get(key: String): Flow<Data> {
return writeTrigger
.map { getInternal(fileNameProvider(key)) }
.filterNotNull()
}
fun getSync(key: String): Data? {
return getInternal(fileNameProvider(key))
}
fun store(key: String, content: Data) {
try {
val json = adapter.toJson(content)
fileReader.rewriteFile(json, fileNameProvider(key))
writeTrigger.tryEmit(Unit)
} catch (e: Throwable) {
throw DataError.PersistenceError.UnableToWriteFile(e)
}
}
private fun getInternal(fileName: String): Data? {
return try {
val json = fileReader.readFile(fileName)
adapter.fromJson(json)
} catch (e: Throwable) {
throw DataError.PersistenceError.UnableToReadFile(e)
}
}
}

View file

@ -1,11 +1,11 @@
package com.tangem.datasource.local.store
package com.tangem.datasource.local.datastore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
internal class RuntimeStore<Key, Data>(private val keyProvider: (Data) -> Key) {
internal class RuntimeDataStore<Key, Data>(private val keyProvider: (Data) -> Key) {
private val store = MutableStateFlow<HashMap<Key, Data>>(hashMapOf())

View file

@ -0,0 +1,28 @@
package com.tangem.datasource.local.token
import com.squareup.moshi.Moshi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.files.FileReader
import com.tangem.datasource.local.datastore.FileDataStore
import kotlinx.coroutines.flow.Flow
internal class FileUserTokensStore(fileReader: FileReader, moshi: Moshi) : UserTokensStore {
private val store = FileDataStore<UserTokensResponse>(
fileNameProvider = { key -> "user_tokens_$key" },
fileReader = fileReader,
adapter = moshi.adapter(UserTokensResponse::class.java),
)
override fun get(userWalletId: String): Flow<UserTokensResponse> {
return store.get(userWalletId)
}
override suspend fun getSync(userWalletId: String): UserTokensResponse? {
return store.getSync(userWalletId)
}
override suspend fun store(userWalletId: String, tokens: UserTokensResponse) {
store.store(userWalletId, tokens)
}
}

View file

@ -0,0 +1,13 @@
package com.tangem.datasource.local.token
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import kotlinx.coroutines.flow.Flow
interface UserTokensStore {
fun get(userWalletId: String): Flow<UserTokensResponse>
suspend fun getSync(userWalletId: String): UserTokensResponse?
suspend fun store(userWalletId: String, tokens: UserTokensResponse)
}

View file

@ -6,4 +6,11 @@ sealed class DataError : Exception() {
object NoInternetConnection : NetworkError()
}
sealed class PersistenceError : DataError() {
data class UnableToReadFile(override val cause: Throwable) : DataError()
data class UnableToWriteFile(override val cause: Throwable) : DataError()
}
}