Updated on 2026-08-14
This commit is contained in:
commit
8eb1a28f29
236 changed files with 3852 additions and 2068 deletions
|
|
@ -15,7 +15,7 @@ import retrofit2.http.Query
|
|||
interface YieldSupplyApi {
|
||||
|
||||
@GET("api/v1/yield/markets")
|
||||
suspend fun getYieldMarkets(@Query("chainId") chainId: Int? = null): ApiResponse<YieldMarketsResponse>
|
||||
suspend fun getYieldMarkets(@Query("chainId") chainId: String? = null): ApiResponse<YieldMarketsResponse>
|
||||
|
||||
@GET("api/v1/yield/token/{chainId}/{tokenAddress}")
|
||||
suspend fun getYieldTokenStatus(
|
||||
|
|
|
|||
|
|
@ -2,8 +2,37 @@ package com.tangem.datasource.api.tangemTech.models.account
|
|||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.datasource.utils.SerializeNulls
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SaveWalletAccountsResponse(
|
||||
@Json(name = "accounts") val accounts: List<WalletAccountDTO>,
|
||||
)
|
||||
@Json(name = "accounts") val accounts: List<AccountDTO>,
|
||||
) {
|
||||
|
||||
@SerializeNulls
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class AccountDTO(
|
||||
@Json(name = "id") val id: String,
|
||||
@Json(name = "name") val name: String?,
|
||||
@Json(name = "derivation") val derivationIndex: Int,
|
||||
@Json(name = "icon") val icon: String,
|
||||
@Json(name = "iconColor") val iconColor: String,
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
operator fun invoke(accounts: List<WalletAccountDTO>): SaveWalletAccountsResponse {
|
||||
return SaveWalletAccountsResponse(
|
||||
accounts = accounts.map { accountDto ->
|
||||
AccountDTO(
|
||||
id = accountDto.id,
|
||||
name = accountDto.name,
|
||||
derivationIndex = accountDto.derivationIndex,
|
||||
icon = accountDto.icon,
|
||||
iconColor = accountDto.iconColor,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import com.tangem.common.json.MoshiJsonConverter
|
|||
import com.tangem.datasource.api.common.adapter.*
|
||||
import com.tangem.datasource.local.config.providers.models.ProviderModel
|
||||
import com.tangem.datasource.local.network.entity.NetworkStatusDM
|
||||
import com.tangem.datasource.utils.SerializeNullsFactory
|
||||
import com.tangem.domain.models.scan.serialization.*
|
||||
import com.tangem.domain.visa.model.VisaActivationRemoteState
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
|
|
@ -28,6 +29,7 @@ class MoshiModule {
|
|||
@NetworkMoshi
|
||||
fun provideNetworkMoshi(): Moshi {
|
||||
return Moshi.Builder()
|
||||
.add(SerializeNullsFactory)
|
||||
.add(
|
||||
PolymorphicJsonAdapterFactory.of(ProviderModel::class.java, "type")
|
||||
.withSubtype(ProviderModel.Public::class.java, "public")
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import android.content.Context
|
|||
import androidx.datastore.core.DataStoreFactory
|
||||
import androidx.datastore.dataStoreFile
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldMarketsResponse
|
||||
import com.tangem.datasource.local.yieldsupply.DefaultYieldMarketsStore
|
||||
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
||||
import com.tangem.datasource.utils.MoshiDataStoreSerializer
|
||||
import com.tangem.datasource.utils.listTypes
|
||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -34,7 +34,7 @@ object YieldSupplyModule {
|
|||
persistenceStore = DataStoreFactory.create(
|
||||
serializer = MoshiDataStoreSerializer(
|
||||
moshi = moshi,
|
||||
types = listTypes<YieldMarketToken>(),
|
||||
types = listTypes<YieldMarketsResponse.MarketDto>(),
|
||||
defaultValue = emptyList(),
|
||||
),
|
||||
produceFile = { context.dataStoreFile(fileName = "yield_markets_cache") },
|
||||
|
|
|
|||
|
|
@ -12,5 +12,7 @@ interface TangemPayStorage {
|
|||
|
||||
suspend fun getOrderId(customerWalletAddress: String): String?
|
||||
|
||||
suspend fun clear(customerWalletAddress: String)
|
||||
suspend fun clearOrderId(customerWalletAddress: String)
|
||||
|
||||
suspend fun clearAll(customerWalletAddress: String)
|
||||
}
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
package com.tangem.datasource.local.yieldsupply
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldMarketsResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
|
||||
internal class DefaultYieldMarketsStore(
|
||||
private val persistenceStore: DataStore<List<YieldMarketToken>>,
|
||||
private val persistenceStore: DataStore<List<YieldMarketsResponse.MarketDto>>,
|
||||
) : YieldMarketsStore {
|
||||
|
||||
override fun get(): Flow<List<YieldMarketToken>> = persistenceStore.data
|
||||
override fun get(): Flow<List<YieldMarketsResponse.MarketDto>> = persistenceStore.data
|
||||
|
||||
override suspend fun getSyncOrNull(): List<YieldMarketToken>? {
|
||||
override suspend fun getSyncOrNull(): List<YieldMarketsResponse.MarketDto>? {
|
||||
return persistenceStore.data.firstOrNull()
|
||||
}
|
||||
|
||||
override suspend fun store(items: List<YieldMarketToken>) {
|
||||
override suspend fun store(items: List<YieldMarketsResponse.MarketDto>) {
|
||||
persistenceStore.updateData { _ -> items }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package com.tangem.datasource.local.yieldsupply
|
||||
|
||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldMarketsResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface YieldMarketsStore {
|
||||
|
||||
fun get(): Flow<List<YieldMarketToken>>
|
||||
fun get(): Flow<List<YieldMarketsResponse.MarketDto>>
|
||||
|
||||
suspend fun getSyncOrNull(): List<YieldMarketToken>?
|
||||
suspend fun getSyncOrNull(): List<YieldMarketsResponse.MarketDto>?
|
||||
|
||||
suspend fun store(items: List<YieldMarketToken>)
|
||||
suspend fun store(items: List<YieldMarketsResponse.MarketDto>)
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.datasource.utils
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class SerializeNulls
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.datasource.utils
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* Factory to serialize nulls in Moshi if the class is annotated with [SerializeNulls].
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object SerializeNullsFactory : JsonAdapter.Factory {
|
||||
|
||||
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
|
||||
val rawType = Types.getRawType(type)
|
||||
if (!rawType.isAnnotationPresent(SerializeNulls::class.java)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val nextAdapter: JsonAdapter<Any> = moshi.nextAdapter(this, type, annotations)
|
||||
|
||||
return nextAdapter.serializeNulls()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.datasource.utils
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.squareup.moshi.Moshi
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
// --- DTO ---
|
||||
@SerializeNulls
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UserWithNulls(val id: String?, val name: String?)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UserWithoutNulls(val id: String?, val name: String?)
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class SerializeNullsFactoryTest {
|
||||
|
||||
private val moshi = Moshi.Builder()
|
||||
.add(SerializeNullsFactory)
|
||||
.build()
|
||||
|
||||
@Test
|
||||
fun `should serialize nulls for annotated class`() {
|
||||
val adapter = moshi.adapter(UserWithNulls::class.java)
|
||||
|
||||
val json = adapter.toJson(UserWithNulls(id = null, name = "John"))
|
||||
|
||||
assertThat(json).isEqualTo("""{"id":null,"name":"John"}""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should skip nulls for non-annotated class`() {
|
||||
val adapter = moshi.adapter(UserWithoutNulls::class.java)
|
||||
|
||||
val json = adapter.toJson(UserWithoutNulls(id = null, name = "John"))
|
||||
|
||||
assertThat(json).isEqualTo("""{"name":"John"}""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize annotated class correctly`() {
|
||||
val adapter = moshi.adapter(UserWithNulls::class.java)
|
||||
|
||||
val json = """{"id":null,"name":"Jane"}"""
|
||||
val result = adapter.fromJson(json)
|
||||
|
||||
assertThat(result).isEqualTo(UserWithNulls(id = null, name = "Jane"))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue