Updated on 2026-08-14

This commit is contained in:
Tangem 2025-05-15 08:39:07 +04:00
parent 90fea21f17
commit 1841d77c4c
13 changed files with 57 additions and 347 deletions

View file

@ -0,0 +1,60 @@
package com.tangem.data.networks.converters
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.domain.tokens.model.NetworkAddress
import com.tangem.utils.converter.TwoWayConverter
import timber.log.Timber
/**
* Converter from [Set<NetworkStatusDM.Address>] to [NetworkAddress] and vice versa
*
[REDACTED_AUTHOR]
*/
internal class NetworkAddressConverter(
private val selectedAddress: String,
) : TwoWayConverter<Set<NetworkStatusDM.Address>, NetworkAddress> {
override fun convert(value: Set<NetworkStatusDM.Address>): NetworkAddress {
val defaultAddress = value
.firstOrNull { it.value == selectedAddress }
?.let(::toNetworkAddress)
requireNotNull(defaultAddress) { "Selected address must not be null" }
return if (value.size != 1) {
NetworkAddress.Selectable(
defaultAddress = defaultAddress,
availableAddresses = value.mapTo(destination = hashSetOf(), transform = ::toNetworkAddress),
)
} else {
NetworkAddress.Single(defaultAddress = defaultAddress)
}
}
override fun convertBack(value: NetworkAddress): Set<NetworkStatusDM.Address> {
return value.availableAddresses
.map { address ->
NetworkStatusDM.Address(
value = address.value,
type = when (address.type) {
NetworkAddress.Address.Type.Primary -> NetworkStatusDM.Address.Type.Primary
NetworkAddress.Address.Type.Secondary -> NetworkStatusDM.Address.Type.Secondary
},
)
}
.toSet()
}
private fun toNetworkAddress(address: NetworkStatusDM.Address): NetworkAddress.Address {
val type = when (address.type) {
NetworkStatusDM.Address.Type.Primary -> NetworkAddress.Address.Type.Primary
NetworkStatusDM.Address.Type.Secondary -> NetworkAddress.Address.Type.Secondary
}
if (address.value.isBlank()) {
Timber.w("Address value is blank")
}
return NetworkAddress.Address(value = address.value, type = type)
}
}

View file

@ -0,0 +1,35 @@
package com.tangem.data.networks.converters
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyAmountStatus
import com.tangem.utils.converter.TwoWayConverter
import com.tangem.utils.extensions.mapNotNullValues
import java.math.BigDecimal
private typealias AmountsDataModel = Map<String, BigDecimal>
private typealias AmountsDomainModel = Map<CryptoCurrency.ID, CryptoCurrencyAmountStatus>
/**
* Converter from [AmountsDataModel] to [AmountsDomainModel] and vice versa
*
[REDACTED_AUTHOR]
*/
internal object NetworkAmountsConverter : TwoWayConverter<AmountsDataModel, AmountsDomainModel> {
override fun convert(value: AmountsDataModel): AmountsDomainModel {
return value
.mapKeys { CryptoCurrency.ID.fromValue(value = it.key) }
.mapValues { (_, amount) -> CryptoCurrencyAmountStatus.Loaded(value = amount) }
}
override fun convertBack(value: AmountsDomainModel): AmountsDataModel {
return value
.mapKeys { (id, _) -> id.value }
.mapNotNullValues { (_, amount) ->
when (amount) {
is CryptoCurrencyAmountStatus.Loaded -> amount.value
is CryptoCurrencyAmountStatus.NotFound -> null
}
}
}
}

View file

@ -0,0 +1,33 @@
package com.tangem.data.networks.converters
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.domain.tokens.model.Network
import com.tangem.utils.converter.TwoWayConverter
/**
* Converter from [NetworkStatusDM.DerivationPath] to [Network.DerivationPath] and vice versa
*
[REDACTED_AUTHOR]
*/
internal object NetworkDerivationPathConverter :
TwoWayConverter<NetworkStatusDM.DerivationPath, Network.DerivationPath> {
override fun convert(value: NetworkStatusDM.DerivationPath): Network.DerivationPath {
return when (value.type) {
NetworkStatusDM.DerivationPath.Type.CARD -> Network.DerivationPath.Card(value.value)
NetworkStatusDM.DerivationPath.Type.CUSTOM -> Network.DerivationPath.Custom(value.value)
NetworkStatusDM.DerivationPath.Type.NONE -> Network.DerivationPath.None
}
}
override fun convertBack(value: Network.DerivationPath): NetworkStatusDM.DerivationPath {
return NetworkStatusDM.DerivationPath(
value = value.value.orEmpty(),
type = when (value) {
is Network.DerivationPath.Card -> NetworkStatusDM.DerivationPath.Type.CARD
is Network.DerivationPath.Custom -> NetworkStatusDM.DerivationPath.Type.CUSTOM
Network.DerivationPath.None -> NetworkStatusDM.DerivationPath.Type.NONE
},
)
}
}

View file

@ -0,0 +1,40 @@
package com.tangem.data.networks.converters
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.utils.converter.Converter
/**
* Converter from [NetworkStatus] to [NetworkStatusDM]
*
[REDACTED_AUTHOR]
*/
internal object NetworkStatusDataModelConverter : Converter<NetworkStatus, NetworkStatusDM?> {
override fun convert(value: NetworkStatus): NetworkStatusDM? {
return when (val status = value.value) {
is NetworkStatus.Verified -> {
NetworkStatusDM.Verified(
networkId = value.network.id,
derivationPath = NetworkDerivationPathConverter.convertBack(value = value.network.derivationPath),
selectedAddress = status.address.defaultAddress.value,
availableAddresses = NetworkAddressConverter(selectedAddress = status.address.defaultAddress.value)
.convertBack(value = status.address),
amounts = NetworkAmountsConverter.convertBack(value = status.amounts),
)
}
is NetworkStatus.NoAccount -> {
NetworkStatusDM.NoAccount(
networkId = value.network.id,
derivationPath = NetworkDerivationPathConverter.convertBack(value = value.network.derivationPath),
selectedAddress = status.address.defaultAddress.value,
availableAddresses = NetworkAddressConverter(selectedAddress = status.address.defaultAddress.value)
.convertBack(value = status.address),
amountToCreateAccount = status.amountToCreateAccount,
errorMessage = status.errorMessage,
)
}
else -> null
}
}
}

View file

@ -1,9 +1,6 @@
package com.tangem.data.networks.converters
import com.tangem.data.networks.models.SimpleNetworkStatus
import com.tangem.datasource.local.network.converter.NetworkAddressConverter
import com.tangem.datasource.local.network.converter.NetworkAmountsConverter
import com.tangem.datasource.local.network.converter.NetworkDerivationPathConverter
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.NetworkStatus

View file

@ -1,25 +1,54 @@
package com.tangem.data.networks.di
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.data.common.currency.CardCryptoCurrencyFactory
import com.tangem.data.networks.repository.DefaultNetworksRepository
import com.tangem.data.networks.store.DefaultNetworksStatusesStoreV2
import com.tangem.data.networks.store.NetworksStatusesStoreV2
import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.local.datastore.RuntimeSharedStore
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.datasource.utils.MoshiDataStoreSerializer
import com.tangem.datasource.utils.mapWithStringKeyTypes
import com.tangem.datasource.utils.setTypes
import com.tangem.domain.networks.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
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
@InstallIn(SingletonComponent::class)
internal object NetworkDataModule {
@Singleton
@Provides
fun providePersistenceNetworksStatusesStore(
@NetworkMoshi moshi: Moshi,
@ApplicationContext context: Context,
dispatchers: CoroutineDispatcherProvider,
): DataStore<Map<String, Set<NetworkStatusDM>>> {
return DataStoreFactory.create(
serializer = MoshiDataStoreSerializer(
moshi = moshi,
types = mapWithStringKeyTypes(valueTypes = setTypes<NetworkStatusDM>()),
defaultValue = emptyMap(),
),
produceFile = { context.dataStoreFile(fileName = "networks_statuses") },
scope = CoroutineScope(context = dispatchers.io + SupervisorJob()),
)
}
@Provides
@Singleton
fun provideNetworksStatusesStoreV2(

View file

@ -1,10 +1,10 @@
package com.tangem.data.networks.store
import androidx.datastore.core.DataStore
import com.tangem.data.networks.converters.NetworkStatusDataModelConverter
import com.tangem.data.networks.converters.SimpleNetworkStatusConverter
import com.tangem.data.networks.models.SimpleNetworkStatus
import com.tangem.datasource.local.datastore.RuntimeSharedStore
import com.tangem.datasource.local.network.converter.NetworkStatusDataModelConverter
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.Network

View file

@ -1,7 +1,7 @@
package com.tangem.data.networks
import com.tangem.data.networks.converters.NetworkStatusDataModelConverter
import com.tangem.data.networks.models.SimpleNetworkStatus
import com.tangem.datasource.local.network.converter.NetworkStatusDataModelConverter
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.domain.tokens.model.NetworkStatus