From effaf2d680114038e0f94082f15f5b508ea86428 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Jul 2023 11:41:13 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/domain/tokens/UserTokensRepository.kt | 6 +-- .../domain/tokens/UserTokensStorageService.kt | 1 + core/datasource/build.gradle.kts | 5 +- .../tangemTech/models/UserTokensResponse.kt | 26 +++++++++- .../com/tangem/datasource/di/MoshiModule.kt | 2 +- .../datasource/di/UserTokensStoreModule.kt | 22 ++++++++ .../local/cache/RuntimeCacheKeysStore.kt | 4 +- .../local/datastore/FileDataStore.kt | 52 +++++++++++++++++++ .../RuntimeDataStore.kt} | 4 +- .../local/token/FileUserTokensStore.kt | 28 ++++++++++ .../datasource/local/token/UserTokensStore.kt | 13 +++++ .../com/tangem/domain/core/error/DataError.kt | 7 +++ 12 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/UserTokensStoreModule.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/datastore/FileDataStore.kt rename core/datasource/src/main/java/com/tangem/datasource/local/{store/RuntimeStore.kt => datastore/RuntimeDataStore.kt} (91%) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/token/FileUserTokensStore.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/token/UserTokensStore.kt diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt index 6842f8a94c..c3ed94f70c 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt @@ -79,8 +79,8 @@ class UserTokensRepository( private fun List.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 diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt index b67bb497de..ff90f83942 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt @@ -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 = MoshiConverter.networkMoshi.adapter(UserTokensResponse::class.java) diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index aa45701df5..34d4fa91a8 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -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) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/UserTokensResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/UserTokensResponse.kt index 180deb01a0..c4b95bba88 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/UserTokensResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/UserTokensResponse.kt @@ -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 = 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, + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt index 0ab6faea17..65668982d4 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt @@ -19,8 +19,8 @@ class MoshiModule { @NetworkMoshi fun provideNetworkMoshi(): Moshi { return Moshi.Builder() - .add(KotlinJsonAdapterFactory()) .add(BigDecimalAdapter()) + .add(KotlinJsonAdapterFactory()) .build() } diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/UserTokensStoreModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/UserTokensStoreModule.kt new file mode 100644 index 0000000000..73d19f644d --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/di/UserTokensStoreModule.kt @@ -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) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/cache/RuntimeCacheKeysStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/cache/RuntimeCacheKeysStore.kt index 229b5ab30c..80bce89b0d 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/cache/RuntimeCacheKeysStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/cache/RuntimeCacheKeysStore.kt @@ -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() diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/FileDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/FileDataStore.kt new file mode 100644 index 0000000000..2da02a5df8 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/FileDataStore.kt @@ -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( + private val fileNameProvider: (key: String) -> String, + private val fileReader: FileReader, + private val adapter: JsonAdapter, +) { + + private val writeTrigger = MutableSharedFlow( + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) + + fun get(key: String): Flow { + 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) + } + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/store/RuntimeStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/RuntimeDataStore.kt similarity index 91% rename from core/datasource/src/main/java/com/tangem/datasource/local/store/RuntimeStore.kt rename to core/datasource/src/main/java/com/tangem/datasource/local/datastore/RuntimeDataStore.kt index 37a05f8d3e..ba55ef6039 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/store/RuntimeStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/RuntimeDataStore.kt @@ -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(private val keyProvider: (Data) -> Key) { +internal class RuntimeDataStore(private val keyProvider: (Data) -> Key) { private val store = MutableStateFlow>(hashMapOf()) diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/FileUserTokensStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/FileUserTokensStore.kt new file mode 100644 index 0000000000..1df1f44428 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/FileUserTokensStore.kt @@ -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( + fileNameProvider = { key -> "user_tokens_$key" }, + fileReader = fileReader, + adapter = moshi.adapter(UserTokensResponse::class.java), + ) + + override fun get(userWalletId: String): Flow { + 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) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/UserTokensStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/UserTokensStore.kt new file mode 100644 index 0000000000..befab5e661 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/UserTokensStore.kt @@ -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 + + suspend fun getSync(userWalletId: String): UserTokensResponse? + + suspend fun store(userWalletId: String, tokens: UserTokensResponse) +} \ No newline at end of file diff --git a/domain/core/src/main/kotlin/com/tangem/domain/core/error/DataError.kt b/domain/core/src/main/kotlin/com/tangem/domain/core/error/DataError.kt index 11567ca43b..a76794c4c4 100644 --- a/domain/core/src/main/kotlin/com/tangem/domain/core/error/DataError.kt +++ b/domain/core/src/main/kotlin/com/tangem/domain/core/error/DataError.kt @@ -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() + } } \ No newline at end of file