Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-19 15:15:33 +05:00
parent e0c101f15f
commit e5e2f4a1e7
13 changed files with 143 additions and 0 deletions

View file

@ -0,0 +1,24 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
alias(deps.plugins.kotlin.kapt)
alias(deps.plugins.hilt.android)
id("configuration")
}
android {
namespace = "com.tangem.data.tokensync"
}
dependencies {
implementation(projects.core.datasource)
implementation(projects.core.utils)
implementation(projects.domain.models)
implementation(deps.hilt.android)
kapt(deps.hilt.kapt)
implementation(deps.androidx.datastore)
implementation(deps.kotlin.coroutines)
implementation(deps.moshi)
}

View file

@ -0,0 +1,24 @@
package com.tangem.data.tokensync.store
import androidx.datastore.core.DataStore
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import kotlinx.coroutines.flow.firstOrNull
internal class DefaultTokenSyncStore(
private val persistenceStore: DataStore<List<UserTokensResponse.Token>>,
) : TokenSyncStore {
override suspend fun get(): List<UserTokensResponse.Token> {
return persistenceStore.data.firstOrNull().orEmpty()
}
override suspend fun append(tokens: List<UserTokensResponse.Token>) {
persistenceStore.updateData { existing ->
(existing + tokens).distinct()
}
}
override suspend fun clear() {
persistenceStore.updateData { emptyList() }
}
}

View file

@ -0,0 +1,12 @@
package com.tangem.data.tokensync.store
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
interface TokenSyncStore {
suspend fun get(): List<UserTokensResponse.Token>
suspend fun append(tokens: List<UserTokensResponse.Token>)
suspend fun clear()
}

View file

@ -0,0 +1,56 @@
package com.tangem.data.tokensync.store
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import com.squareup.moshi.Moshi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.utils.MoshiDataStoreSerializer
import com.tangem.datasource.utils.listTypes
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.utils.coroutines.AppCoroutineScope
import dagger.hilt.android.qualifiers.ApplicationContext
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class TokenSyncStoreFactory @Inject constructor(
@NetworkMoshi private val moshi: Moshi,
@ApplicationContext private val context: Context,
private val appScope: AppCoroutineScope,
) {
private val stores = ConcurrentHashMap<String, TokenSyncStore>()
fun provide(userWalletId: UserWalletId): TokenSyncStore {
val userWalletStringId = userWalletId.formatted()
return stores.computeIfAbsent(userWalletStringId) {
DefaultTokenSyncStore(
persistenceStore = createPersistenceStore(
fileName = "token_sync_$userWalletStringId",
types = listTypes<UserTokensResponse.Token>(),
defaultValue = emptyList(),
),
)
}
}
private fun <T> createPersistenceStore(
fileName: String,
types: java.lang.reflect.ParameterizedType,
defaultValue: T,
): DataStore<T> = DataStoreFactory.create(
serializer = MoshiDataStoreSerializer(
moshi = moshi,
types = types,
defaultValue = defaultValue,
),
produceFile = { context.dataStoreFile(fileName = fileName) },
scope = appScope,
)
private fun UserWalletId.formatted(): String = stringValue.lowercase()
}

View file

@ -18,6 +18,7 @@ import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.blockchain.nft.models.NFTAsset
import com.tangem.blockchain.nft.models.NFTCollection
import com.tangem.blockchain.tokenbalance.models.TokenBalance
import com.tangem.blockchain.transactionhistory.models.TransactionHistoryRequest
import com.tangem.blockchain.yieldsupply.YieldSupplyContractCallDataProviderFactory
import com.tangem.blockchainsdk.BlockchainSDKFactory
@ -769,6 +770,17 @@ internal class DefaultWalletManagersFacade @Inject constructor(
return blockchain.getNFTExploreUrl(assetIdentifier)
}
override suspend fun getTokenBalances(userWalletId: UserWalletId, network: Network): List<TokenBalance> {
val blockchain = network.toBlockchain()
val walletManager = getOrCreateWalletManager(
userWalletId = userWalletId,
blockchain = blockchain,
derivationPath = network.derivationPath.value,
) ?: return emptyList()
val address = walletManager.wallet.address
return walletManager.getTokenBalances(address)
}
override suspend fun isAccountInitialized(userWalletId: UserWalletId, network: Network): Boolean {
val walletManager = getOrCreateWalletManager(userWalletId = userWalletId, network = network)
val initializableAccountWalletManger = walletManager as? InitializableAccount ?: return true