From 2e14534db39f9c5075b96cf6d49c4b0f58a35ccb Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Mar 2025 15:09:44 +0300 Subject: [PATCH 1/5] Updated on 2026-08-14 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index f5fd46675c..699b0b8822 100644 --- a/version.properties +++ b/version.properties @@ -1 +1 @@ -versionName=5.21.1 \ No newline at end of file +versionName=5.21.2 \ No newline at end of file From 66c6e8e34da450fc7e29ab31fce736dc629215cf Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 7 Mar 2025 17:48:01 +0300 Subject: [PATCH 2/5] Updated on 2026-08-14 --- .../exchangeServices/DefaultRampManager.kt | 5 ++- .../datasource/di/ExpressAssetsStoreModule.kt | 30 +++++++++++++- .../swap/DefaultExpressServiceLoader.kt | 18 ++++---- .../swap/ExpressServiceLoader.kt | 4 +- .../local/token/DefaultExpressAssetsStore.kt | 41 +++++++++++++++++-- 5 files changed, 82 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt index ca9bb24e80..c9b24eeb0a 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt @@ -26,6 +26,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.runCatching import com.tangem.utils.isNullOrZero import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.withContext @Suppress("LongParameterList") @@ -134,8 +135,10 @@ internal class DefaultRampManager( userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, ): ExchangeableState { + val asset = expressServiceLoader.getInitializationStatus(userWalletId).firstOrNull() + ?: return ExchangeableState.Error return withContext(dispatchers.io) { - when (val asset = expressServiceLoader.getInitializationStatus(userWalletId).value) { + when (asset) { is Lce.Error -> ExchangeableState.Error is Lce.Loading -> ExchangeableState.Loading is Lce.Content -> { diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt index cf51b2b006..0799c40b41 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt @@ -1,12 +1,23 @@ package com.tangem.datasource.di +import android.content.Context +import androidx.datastore.core.DataStoreFactory +import androidx.datastore.dataStoreFile +import com.squareup.moshi.Moshi +import com.tangem.datasource.api.express.models.response.Asset import com.tangem.datasource.local.datastore.RuntimeDataStore import com.tangem.datasource.local.token.DefaultExpressAssetsStore import com.tangem.datasource.local.token.ExpressAssetsStore +import com.tangem.datasource.utils.MoshiDataStoreSerializer +import com.tangem.datasource.utils.mapWithStringKeyTypes +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob import javax.inject.Singleton @Module @@ -15,7 +26,22 @@ internal object ExpressAssetsStoreModule { @Provides @Singleton - fun provideExpressAssetsStore(): ExpressAssetsStore { - return DefaultExpressAssetsStore(dataStore = RuntimeDataStore()) + fun provideExpressAssetsStore( + @NetworkMoshi moshi: Moshi, + @ApplicationContext context: Context, + dispatchers: CoroutineDispatcherProvider, + ): ExpressAssetsStore { + return DefaultExpressAssetsStore( + persistenceStore = DataStoreFactory.create( + serializer = MoshiDataStoreSerializer( + moshi = moshi, + types = mapWithStringKeyTypes(), + defaultValue = emptyMap(), + ), + produceFile = { context.dataStoreFile("express_assets") }, + scope = CoroutineScope(context = dispatchers.io + SupervisorJob()), + ), + runtimeStore = RuntimeDataStore(), + ) } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt index c2818ecd87..b966a12e0e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt @@ -12,7 +12,9 @@ import com.tangem.domain.core.utils.lceError import com.tangem.domain.core.utils.lceLoading import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.update import kotlinx.coroutines.withContext import timber.log.Timber @@ -41,8 +43,6 @@ internal class DefaultExpressServiceLoader @Inject constructor( withContext(dispatchers.io) { val initializationStatus = getInitializationStatusInternal(userWalletId) - initializationStatus.update { lceLoading() } - try { if (userTokens.isNotEmpty()) { val response = tangemExpressApi.getAssets( @@ -54,22 +54,24 @@ internal class DefaultExpressServiceLoader @Inject constructor( initializationStatus.update { response.lceContent() } } } catch (e: Throwable) { - initializationStatus.update { e.lceError() } + if (expressAssetsStore.getSyncOrNull(userWalletId) == null) { + initializationStatus.update { e.lceError() } + } Timber.e(e, "Unable to fetch assets for: ${userWalletId.stringValue}") } } } - override fun getInitializationStatus(userWalletId: UserWalletId): InitializationStatusFlow { - return getInitializationStatusInternal(userWalletId) + override fun getInitializationStatus(userWalletId: UserWalletId): Flow>> { + return flow { getInitializationStatusInternal(userWalletId).collect { emit(it) } } } - private fun getInitializationStatusInternal(userWalletId: UserWalletId): InitializationStatusFlow { + private suspend fun getInitializationStatusInternal(userWalletId: UserWalletId): InitializationStatusFlow { val initializationStatus = initializationStatuses.value.get(key = userWalletId) - if (initializationStatus != null) return initializationStatus - val default: InitializationStatusFlow = MutableStateFlow(value = lceLoading()) + val cached = expressAssetsStore.getSyncOrNull(userWalletId) + val default: InitializationStatusFlow = MutableStateFlow(value = cached?.lceContent() ?: lceLoading()) initializationStatuses.update { it.toMutableMap().apply { diff --git a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt index 72e59dba3a..f73ee82700 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt @@ -4,7 +4,7 @@ import com.tangem.datasource.api.express.models.request.LeastTokenInfo import com.tangem.datasource.api.express.models.response.Asset import com.tangem.domain.core.lce.Lce import com.tangem.domain.wallets.models.UserWalletId -import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.Flow /** * Express service loader @@ -17,5 +17,5 @@ interface ExpressServiceLoader { suspend fun update(userWalletId: UserWalletId, userTokens: List) /** Get initialization status by [userWalletId] */ - fun getInitializationStatus(userWalletId: UserWalletId): StateFlow>> + fun getInitializationStatus(userWalletId: UserWalletId): Flow>> } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultExpressAssetsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultExpressAssetsStore.kt index c67abc06e5..5d941ccc5f 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultExpressAssetsStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultExpressAssetsStore.kt @@ -1,18 +1,53 @@ package com.tangem.datasource.local.token +import androidx.datastore.core.DataStore import com.tangem.datasource.api.express.models.response.Asset import com.tangem.datasource.local.datastore.core.StringKeyDataStore import com.tangem.domain.wallets.models.UserWalletId +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.launch + +internal typealias AssetsByWalletId = Map> internal class DefaultExpressAssetsStore( - private val dataStore: StringKeyDataStore>, + private val persistenceStore: DataStore, + private val runtimeStore: StringKeyDataStore>, ) : ExpressAssetsStore { override suspend fun getSyncOrNull(userWalletId: UserWalletId): List? { - return dataStore.getSyncOrNull(userWalletId.stringValue) + val runtimeAssets = runtimeStore.getSyncOrNull(userWalletId.stringValue) + + if (runtimeAssets != null) { + return runtimeAssets + } + + val cachedAssets = getCachedAssets(userWalletId) + + return if (cachedAssets != null) { + runtimeStore.store(userWalletId.stringValue, cachedAssets) + cachedAssets + } else { + null + } + } + + private suspend fun getCachedAssets(userWalletId: UserWalletId): List? { + return persistenceStore.data.firstOrNull().orEmpty()[userWalletId.stringValue] } override suspend fun store(userWalletId: UserWalletId, item: List) { - dataStore.store(userWalletId.stringValue, item) + coroutineScope { + launch { + runtimeStore.store(userWalletId.stringValue, item) + } + launch { + persistenceStore.updateData { + it.toMutableMap().apply { + put(userWalletId.stringValue, item) + } + } + } + } } } \ No newline at end of file From c86e5ba2fb84ca26846deb27e9b14e393dfff690 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Mar 2025 15:09:59 +0300 Subject: [PATCH 3/5] Updated on 2026-08-14 --- .../java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt index 0799c40b41..512085bd3e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/ExpressAssetsStoreModule.kt @@ -9,6 +9,7 @@ import com.tangem.datasource.local.datastore.RuntimeDataStore import com.tangem.datasource.local.token.DefaultExpressAssetsStore import com.tangem.datasource.local.token.ExpressAssetsStore import com.tangem.datasource.utils.MoshiDataStoreSerializer +import com.tangem.datasource.utils.listTypes import com.tangem.datasource.utils.mapWithStringKeyTypes import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module @@ -35,7 +36,7 @@ internal object ExpressAssetsStoreModule { persistenceStore = DataStoreFactory.create( serializer = MoshiDataStoreSerializer( moshi = moshi, - types = mapWithStringKeyTypes(), + types = mapWithStringKeyTypes(listTypes()), defaultValue = emptyMap(), ), produceFile = { context.dataStoreFile("express_assets") }, From 59de366001f5e82f7a2d8b911cd77c38d29e4974 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Mar 2025 15:53:14 +0300 Subject: [PATCH 4/5] Updated on 2026-08-14 --- .../tangem/tap/network/exchangeServices/DefaultRampManager.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt index c9b24eeb0a..d53b637ce1 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt @@ -135,9 +135,9 @@ internal class DefaultRampManager( userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, ): ExchangeableState { - val asset = expressServiceLoader.getInitializationStatus(userWalletId).firstOrNull() - ?: return ExchangeableState.Error return withContext(dispatchers.io) { + val asset = expressServiceLoader.getInitializationStatus(userWalletId).firstOrNull() + ?: return@withContext ExchangeableState.Loading when (asset) { is Lce.Error -> ExchangeableState.Error is Lce.Loading -> ExchangeableState.Loading From 3ce3f3e4462b4aa8ab6820a15da0c94eb11b31f6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Mar 2025 12:53:36 +0000 Subject: [PATCH 5/5] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index df3e3f8b44..7b378fad02 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,7 +1,7 @@ [versions] -tangemBlockchainSdk = "release-app_5.21-976" +tangemBlockchainSdk = "develop-977" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.21-438" +tangemCardSdk = "develop-439" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem-developments8" #tangemVico = "0.0.1" # Keep it! - used for local builds ^