Updated on 2026-08-14
This commit is contained in:
commit
1f6cbc7ed0
537 changed files with 6377 additions and 12897 deletions
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.datasource.api.common.config
|
||||
|
||||
import com.tangem.datasource.BuildConfig
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.datasource.utils.RequestHeader
|
||||
import com.tangem.lib.auth.ExpressAuthProvider
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -10,12 +10,12 @@ import com.tangem.utils.version.AppVersionProvider
|
|||
/**
|
||||
* Express [ApiConfig]
|
||||
*
|
||||
* @property configManager config manager
|
||||
* @property expressAuthProvider express auth provider
|
||||
* @property appVersionProvider app version provider
|
||||
* @property environmentConfigStorage environment config storage
|
||||
* @property expressAuthProvider express auth provider
|
||||
* @property appVersionProvider app version provider
|
||||
*/
|
||||
internal class Express(
|
||||
private val configManager: ConfigManager,
|
||||
private val environmentConfigStorage: EnvironmentConfigStorage,
|
||||
private val expressAuthProvider: ExpressAuthProvider,
|
||||
private val appVersionProvider: AppVersionProvider,
|
||||
) : ApiConfig() {
|
||||
|
|
@ -56,9 +56,9 @@ internal class Express(
|
|||
|
||||
private fun getApiKey(isProd: Boolean): String {
|
||||
return if (isProd) {
|
||||
configManager.config.express
|
||||
environmentConfigStorage.getConfigSync().express
|
||||
} else {
|
||||
configManager.config.devExpress
|
||||
environmentConfigStorage.getConfigSync().devExpress
|
||||
}
|
||||
?.apiKey
|
||||
?: error("No express config provided")
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ interface TangemTechMarketsApi {
|
|||
@Query("interval") interval: String,
|
||||
): ApiResponse<TokenMarketChartResponse>
|
||||
|
||||
@GET("coins/{coin_id}/exchanges")
|
||||
suspend fun getCoinExchanges(@Path("coin_id") coinId: String): ApiResponse<TokenMarketExchangesResponse>
|
||||
|
||||
@GET("coins/history_preview")
|
||||
suspend fun getCoinsListCharts(
|
||||
@Query("coin_ids") coinIds: String,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.datasource.api.markets.models.response
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Token market exchanges response
|
||||
*
|
||||
* @property exchanges list of exchanges
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TokenMarketExchangesResponse(
|
||||
@Json(name = "exchanges") val exchanges: List<Exchange>,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Exchange
|
||||
*
|
||||
* @property id id
|
||||
* @property name name
|
||||
* @property imageUrl image url
|
||||
* @property isCentralized CEX (true), DEX (false)
|
||||
* @property volumeInUsd aggregated volume in USD
|
||||
* @property trustScore trust score
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Exchange(
|
||||
@Json(name = "exchange_id") val id: String,
|
||||
@Json(name = "name") val name: String,
|
||||
@Json(name = "image") val imageUrl: String?,
|
||||
@Json(name = "centralized") val isCentralized: Boolean,
|
||||
@Json(name = "volume_usd") val volumeInUsd: BigDecimal,
|
||||
@Json(name = "trust_score") val trustScore: Int?,
|
||||
)
|
||||
}
|
||||
|
|
@ -30,6 +30,8 @@ data class TokenMarketInfoResponse(
|
|||
val links: Links?,
|
||||
@Json(name = "price_performance")
|
||||
val pricePerformance: PricePerformance?,
|
||||
@Json(name = "exchanges_amount")
|
||||
val exchangesAmount: Int?,
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.datasource.api.onramp
|
||||
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.onramp.models.request.OnrampPairsRequest
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampDataResponse
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampQuoteResponse
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampStatusResponse
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCurrencyDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Query
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass", "TooManyFunctions")
|
||||
interface OnrampApi {
|
||||
|
||||
@GET("currencies")
|
||||
suspend fun getCurrencies(): ApiResponse<List<OnrampCurrencyDTO>>
|
||||
|
||||
@GET("countries")
|
||||
suspend fun getCountries(): ApiResponse<List<OnrampCountryDTO>>
|
||||
|
||||
@GET("country-by-ip")
|
||||
suspend fun getCountryByIp(): ApiResponse<OnrampCountryDTO>
|
||||
|
||||
@GET("payment-methods")
|
||||
suspend fun getPaymentMethods(): ApiResponse<List<PaymentMethodDTO>>
|
||||
|
||||
@POST("onramp-pairs")
|
||||
suspend fun getPairs(@Body body: OnrampPairsRequest): ApiResponse<List<OnrampPairDTO>>
|
||||
|
||||
@GET("onramp-quote")
|
||||
suspend fun getQuote(
|
||||
@Query("fromCurrencyCode") fromCurrencyCode: String,
|
||||
@Query("toContractAddress") toContractAddress: String,
|
||||
@Query("toNetwork") toNetwork: String,
|
||||
@Query("paymentMethod") paymentMethod: String,
|
||||
@Query("countryCode") countryCode: String,
|
||||
@Query("fromAmount") fromAmount: String,
|
||||
@Query("toDecimals") toDecimals: Int,
|
||||
@Query("providerId") providerId: String,
|
||||
): ApiResponse<OnrampQuoteResponse>
|
||||
|
||||
@GET("onramp-data")
|
||||
suspend fun getData(
|
||||
@Query("fromCurrencyCode") fromCurrencyCode: String,
|
||||
@Query("toContractAddress") toContractAddress: String,
|
||||
@Query("toNetwork") toNetwork: String,
|
||||
@Query("paymentMethod") paymentMethod: String,
|
||||
@Query("countryCode") countryCode: String,
|
||||
@Query("fromAmount") fromAmount: String,
|
||||
@Query("toDecimals") toDecimals: Int,
|
||||
@Query("providerId") providerId: String,
|
||||
@Query("toAddress") toAddress: String,
|
||||
@Query("redirectUrl") redirectUrl: String,
|
||||
@Query("language") language: String?,
|
||||
@Query("theme") theme: String?,
|
||||
@Query("requestId") requestId: String,
|
||||
): ApiResponse<OnrampDataResponse>
|
||||
|
||||
@GET("onramp-status")
|
||||
suspend fun getStatus(@Query("txId") txId: String): ApiResponse<OnrampStatusResponse>
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.datasource.api.onramp.models.common
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampDestinationDTO(
|
||||
@Json(name = "contractAddress")
|
||||
val contractAddress: String,
|
||||
|
||||
@Json(name = "network")
|
||||
val network: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.datasource.api.onramp.models.request
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.datasource.api.onramp.models.common.OnrampDestinationDTO
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampPairsRequest(
|
||||
@Json(name = "fromCurrencyCode")
|
||||
val fromCurrencyCode: String?,
|
||||
|
||||
@Json(name = "countryCode")
|
||||
val countryCode: String,
|
||||
|
||||
@Json(name = "to")
|
||||
val to: List<OnrampDestinationDTO>,
|
||||
)
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.tangem.datasource.api.onramp.models.response
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
data class OnrampDataResponseWithTxDetails(
|
||||
val dataResponse: OnrampDataResponse,
|
||||
val txDetails: OnrampTxDetails,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampDataResponse(
|
||||
@Json(name = "txId")
|
||||
val txId: String,
|
||||
|
||||
@Json(name = "dataJson")
|
||||
val dataJson: String,
|
||||
|
||||
@Json(name = "signature")
|
||||
val signature: String,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampTxDetails(
|
||||
@Json(name = "fromCurrencyCode")
|
||||
val fromCurrencyCode: String,
|
||||
|
||||
@Json(name = "toContractAddress")
|
||||
val toContractAddress: String,
|
||||
|
||||
@Json(name = "toNetwork")
|
||||
val toNetwork: String,
|
||||
|
||||
@Json(name = "paymentMethod")
|
||||
val paymentMethod: String,
|
||||
|
||||
@Json(name = "countryCode")
|
||||
val countryCode: String,
|
||||
|
||||
@Json(name = "fromAmount")
|
||||
val fromAmount: String,
|
||||
|
||||
@Json(name = "toDecimals")
|
||||
val toDecimals: Int,
|
||||
|
||||
@Json(name = "providerId")
|
||||
val providerId: String,
|
||||
|
||||
@Json(name = "toAddress")
|
||||
val toAddress: String,
|
||||
|
||||
@Json(name = "redirectUrl")
|
||||
val redirectUrl: String,
|
||||
|
||||
@Json(name = "language")
|
||||
val language: String?,
|
||||
|
||||
@Json(name = "theme")
|
||||
val theme: String?,
|
||||
|
||||
@Json(name = "requestId")
|
||||
val requestId: String,
|
||||
|
||||
@Json(name = "externalTxId")
|
||||
val externalTxId: String,
|
||||
|
||||
@Json(name = "widgetUrl")
|
||||
val widgetUrl: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tangem.datasource.api.onramp.models.response
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampQuoteResponse(
|
||||
@Json(name = "fromCurrencyCode")
|
||||
val fromCurrencyCode: String,
|
||||
|
||||
@Json(name = "toContractAddress")
|
||||
val toContractAddress: String,
|
||||
|
||||
@Json(name = "toNetwork")
|
||||
val toNetwork: String,
|
||||
|
||||
@Json(name = "paymentMethod")
|
||||
val paymentMethod: String,
|
||||
|
||||
@Json(name = "countryCode")
|
||||
val countryCode: String,
|
||||
|
||||
@Json(name = "fromAmount")
|
||||
val fromAmount: String,
|
||||
|
||||
@Json(name = "toAmount")
|
||||
val toAmount: String,
|
||||
|
||||
@Json(name = "toDecimals")
|
||||
val toDecimals: Int,
|
||||
|
||||
@Json(name = "providerId")
|
||||
val providerId: String,
|
||||
|
||||
@Json(name = "minFromAmount")
|
||||
val minFromAmount: String,
|
||||
|
||||
@Json(name = "maxFromAmount")
|
||||
val maxFromAmount: String,
|
||||
|
||||
@Json(name = "minToAmount")
|
||||
val minToAmount: String,
|
||||
|
||||
@Json(name = "maxToAmount")
|
||||
val maxToAmount: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.datasource.api.onramp.models.response
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampStatusResponse(
|
||||
@Json(name = "txId")
|
||||
val txId: String,
|
||||
|
||||
@Json(name = "providerId")
|
||||
val providerId: String,
|
||||
|
||||
@Json(name = "payoutAddress")
|
||||
val payoutAddress: String,
|
||||
|
||||
// @Json(name = "status")
|
||||
// val status: ???
|
||||
|
||||
@Json(name = "failReason")
|
||||
val failReason: String?,
|
||||
|
||||
@Json(name = "externalTxId")
|
||||
val externalTxId: String,
|
||||
|
||||
@Json(name = "externalTxUrl")
|
||||
val externalTxUrl: String?,
|
||||
|
||||
@Json(name = "payoutHash")
|
||||
val payoutHash: String?,
|
||||
|
||||
@Json(name = "createdAt")
|
||||
val createdAt: String,
|
||||
|
||||
@Json(name = "fromCurrencyCode")
|
||||
val fromCurrencyCode: String,
|
||||
|
||||
@Json(name = "fromAmount")
|
||||
val fromAmount: String,
|
||||
|
||||
@Json(name = "toContractAddress")
|
||||
val toContractAddress: String,
|
||||
|
||||
@Json(name = "toNetwork")
|
||||
val toNetwork: String,
|
||||
|
||||
@Json(name = "toDecimals")
|
||||
val toDecimals: String,
|
||||
|
||||
@Json(name = "toAmount")
|
||||
val toAmount: String,
|
||||
|
||||
@Json(name = "toActualAmount")
|
||||
val toActualAmount: String,
|
||||
|
||||
@Json(name = "paymentMethod")
|
||||
val paymentMethod: String,
|
||||
|
||||
@Json(name = "countryCode")
|
||||
val countryCode: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.datasource.api.onramp.models.response.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampCountryDTO(
|
||||
@Json(name = "name")
|
||||
val name: String,
|
||||
|
||||
@Json(name = "code")
|
||||
val code: String,
|
||||
|
||||
@Json(name = "image")
|
||||
val image: String,
|
||||
|
||||
@Json(name = "alpha3")
|
||||
val alpha3: String,
|
||||
|
||||
@Json(name = "continent")
|
||||
val continent: String,
|
||||
|
||||
@Json(name = "defaultCurrency")
|
||||
val defaultCurrency: OnrampCurrencyDTO,
|
||||
|
||||
@Json(name = "onrampAvailable")
|
||||
val onrampAvailable: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.datasource.api.onramp.models.response.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampCurrencyDTO(
|
||||
@Json(name = "name")
|
||||
val name: String,
|
||||
|
||||
@Json(name = "code")
|
||||
val code: String,
|
||||
|
||||
@Json(name = "image")
|
||||
val image: String,
|
||||
|
||||
@Json(name = "precision")
|
||||
val precision: Int,
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.datasource.api.onramp.models.response.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.datasource.api.onramp.models.common.OnrampDestinationDTO
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampPairDTO(
|
||||
@Json(name = "fromCurrencyCode")
|
||||
val fromCurrencyCode: String?,
|
||||
|
||||
@Json(name = "to")
|
||||
val to: OnrampDestinationDTO,
|
||||
|
||||
@Json(name = "providers")
|
||||
val providers: List<OnrampProviderDTO>,
|
||||
)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.datasource.api.onramp.models.response.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class OnrampProviderDTO(
|
||||
@Json(name = "providerId")
|
||||
val providerId: String,
|
||||
|
||||
@Json(name = "paymentMethods")
|
||||
val paymentMethods: List<String>,
|
||||
)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.datasource.api.onramp.models.response.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class PaymentMethodDTO(
|
||||
@Json(name = "id")
|
||||
val id: String,
|
||||
|
||||
@Json(name = "name")
|
||||
val name: String,
|
||||
|
||||
@Json(name = "image")
|
||||
val image: String,
|
||||
)
|
||||
|
|
@ -5,9 +5,7 @@ import com.tangem.datasource.api.stakekit.models.request.*
|
|||
import com.tangem.datasource.api.stakekit.models.response.EnabledYieldsResponse
|
||||
import com.tangem.datasource.api.stakekit.models.response.EnterActionResponse
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.TokenWithYieldDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.transaction.StakingGasEstimateDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.transaction.StakingTransactionDTO
|
||||
import retrofit2.http.*
|
||||
|
|
@ -16,7 +14,7 @@ import retrofit2.http.*
|
|||
interface StakeKitApi {
|
||||
|
||||
@GET("yields/enabled")
|
||||
suspend fun getMultipleYields(
|
||||
suspend fun getEnabledYields(
|
||||
@Query("preferredValidatorsOnly") preferredValidatorsOnly: Boolean? = null,
|
||||
@Query("ledgerWalletAPICompatible") ledgerWalletAPICompatible: Boolean? = null,
|
||||
@Query("type") type: YieldType? = null,
|
||||
|
|
@ -26,12 +24,6 @@ interface StakeKitApi {
|
|||
@Query("limit") limit: Int? = null,
|
||||
): ApiResponse<EnabledYieldsResponse>
|
||||
|
||||
@GET("yields/{integrationId}")
|
||||
suspend fun getSingleYield(
|
||||
@Path("integrationId") integrationId: String,
|
||||
@Query("ledgerWalletAPICompatible") ledgerWalletAPICompatible: Boolean = false,
|
||||
): ApiResponse<YieldDTO>
|
||||
|
||||
@POST("yields/balances")
|
||||
suspend fun getMultipleYieldBalances(
|
||||
@Body body: List<YieldBalanceRequestBody>,
|
||||
|
|
@ -43,9 +35,6 @@ interface StakeKitApi {
|
|||
@Body body: YieldBalanceRequestBody,
|
||||
): ApiResponse<List<BalanceDTO>>
|
||||
|
||||
@GET("tokens")
|
||||
suspend fun getTokens(): ApiResponse<List<TokenWithYieldDTO>>
|
||||
|
||||
@POST("actions/enter")
|
||||
suspend fun createEnterAction(@Body body: ActionRequestBody): ApiResponse<EnterActionResponse>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.datasource.api.stakekit.models.response.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TokenWithYieldDTO(
|
||||
@Json(name = "token") val token: TokenDTO,
|
||||
@Json(name = "availableYields") val availableYieldIds: List<String>,
|
||||
)
|
||||
|
|
@ -4,7 +4,7 @@ import com.tangem.datasource.api.common.response.ApiResponse
|
|||
import com.tangem.datasource.api.promotion.models.PromotionInfoResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.*
|
||||
import com.tangem.datasource.api.utils.ReadTimeout
|
||||
import com.tangem.datasource.config.models.ProviderModel
|
||||
import com.tangem.datasource.local.config.providers.models.ProviderModel
|
||||
import retrofit2.http.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.datasource.api.tangemTech.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GeoResponse(
|
||||
@Json(name = "code") val code: String,
|
||||
)
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package com.tangem.datasource.config
|
||||
|
||||
import com.tangem.datasource.config.models.Config
|
||||
import com.tangem.datasource.config.models.ConfigModel
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface ConfigManager {
|
||||
|
||||
val config: Config
|
||||
|
||||
suspend fun load(configLoader: Loader<ConfigModel>, onComplete: ((config: Config) -> Unit)? = null)
|
||||
|
||||
fun turnOff(name: String)
|
||||
|
||||
fun resetToDefault(name: String)
|
||||
|
||||
companion object {
|
||||
const val IS_CREATING_TWIN_CARDS_ALLOWED = "isCreatingTwinCardsAllowed"
|
||||
const val IS_TOP_UP_ENABLED = "isTopUpEnabled"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
package com.tangem.datasource.config
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.datasource.config.ConfigManager.Companion.IS_CREATING_TWIN_CARDS_ALLOWED
|
||||
import com.tangem.datasource.config.ConfigManager.Companion.IS_TOP_UP_ENABLED
|
||||
import com.tangem.datasource.config.models.Config
|
||||
import com.tangem.datasource.config.models.ConfigModel
|
||||
import com.tangem.datasource.config.models.ConfigValueModel
|
||||
import com.tangem.datasource.config.models.FeatureModel
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
internal class ConfigManagerImpl @Inject constructor() : ConfigManager {
|
||||
|
||||
override var config: Config = Config()
|
||||
private set
|
||||
|
||||
private var defaultConfig = Config()
|
||||
|
||||
override suspend fun load(configLoader: Loader<ConfigModel>, onComplete: ((config: Config) -> Unit)?) {
|
||||
configLoader.load { configModel ->
|
||||
setupFeature(configModel.features)
|
||||
setupConfigValues(configModel.configValues)
|
||||
onComplete?.invoke(config)
|
||||
}
|
||||
}
|
||||
|
||||
override fun turnOff(name: String) {
|
||||
when (name) {
|
||||
IS_TOP_UP_ENABLED -> config = config.copy(isTopUpEnabled = false)
|
||||
IS_CREATING_TWIN_CARDS_ALLOWED -> config = config.copy(isCreatingTwinCardsAllowed = false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun resetToDefault(name: String) {
|
||||
when (name) {
|
||||
IS_TOP_UP_ENABLED -> {
|
||||
config = config.copy(isTopUpEnabled = defaultConfig.isTopUpEnabled)
|
||||
}
|
||||
IS_CREATING_TWIN_CARDS_ALLOWED -> {
|
||||
config = config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupFeature(featureModel: FeatureModel?) {
|
||||
val model = featureModel ?: return
|
||||
|
||||
config = config.copy(
|
||||
isTopUpEnabled = model.isTopUpEnabled,
|
||||
isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed,
|
||||
)
|
||||
|
||||
defaultConfig = defaultConfig.copy(
|
||||
isTopUpEnabled = model.isTopUpEnabled,
|
||||
isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed,
|
||||
)
|
||||
}
|
||||
|
||||
private fun setupConfigValues(configValues: ConfigValueModel?) {
|
||||
val values = configValues ?: return
|
||||
|
||||
config = createConfig(config, values)
|
||||
defaultConfig = config.copy()
|
||||
}
|
||||
|
||||
private fun createConfig(config: Config, configValues: ConfigValueModel): Config {
|
||||
return config.copy(
|
||||
coinMarketCapKey = configValues.coinMarketCapKey,
|
||||
moonPayApiKey = configValues.moonPayApiKey,
|
||||
moonPayApiSecretKey = configValues.moonPayApiSecretKey,
|
||||
mercuryoWidgetId = configValues.mercuryoWidgetId,
|
||||
mercuryoSecret = configValues.mercuryoSecret,
|
||||
blockchainSdkConfig = BlockchainSdkConfig(
|
||||
blockchairCredentials = BlockchairCredentials(
|
||||
apiKey = configValues.blockchairApiKeys,
|
||||
authToken = configValues.blockchairAuthorizationToken,
|
||||
),
|
||||
blockcypherTokens = configValues.blockcypherTokens,
|
||||
quickNodeSolanaCredentials = QuickNodeCredentials(
|
||||
apiKey = configValues.quiknodeApiKey,
|
||||
subdomain = configValues.quiknodeSubdomain,
|
||||
),
|
||||
quickNodeBscCredentials = QuickNodeCredentials(
|
||||
apiKey = configValues.bscQuiknodeApiKey,
|
||||
subdomain = configValues.bscQuiknodeSubdomain,
|
||||
),
|
||||
infuraProjectId = configValues.infuraProjectId,
|
||||
tronGridApiKey = configValues.tronGridApiKey,
|
||||
nowNodeCredentials = NowNodeCredentials(configValues.nowNodesApiKey),
|
||||
getBlockCredentials = createGetBlockCredentials(configValues),
|
||||
kaspaSecondaryApiUrl = configValues.kaspaSecondaryApiUrl,
|
||||
tonCenterCredentials = TonCenterCredentials(
|
||||
mainnetApiKey = configValues.tonCenterKeys.mainnet,
|
||||
testnetApiKey = configValues.tonCenterKeys.testnet,
|
||||
),
|
||||
chiaFireAcademyApiKey = configValues.chiaFireAcademyApiKey,
|
||||
chiaTangemApiKey = configValues.chiaTangemApiKey,
|
||||
hederaArkhiaApiKey = configValues.hederaArkhiaKey,
|
||||
polygonScanApiKey = configValues.polygonScanApiKey,
|
||||
bittensorDwellirApiKey = configValues.bittensorDwellirApiKey,
|
||||
bittensorOnfinalityApiKey = configValues.bittensorOnfinalityKey,
|
||||
koinosProApiKey = configValues.koinosProApiKey,
|
||||
),
|
||||
amplitudeApiKey = configValues.amplitudeApiKey,
|
||||
sprinklr = configValues.sprinklr,
|
||||
walletConnectProjectId = configValues.walletConnectProjectId,
|
||||
tangemComAuthorization = configValues.tangemComAuthorization,
|
||||
express = configValues.express,
|
||||
devExpress = configValues.devExpress,
|
||||
stakeKitApiKey = configValues.stakeKitApiKey,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createGetBlockCredentials(configValues: ConfigValueModel): GetBlockCredentials? {
|
||||
return configValues.getBlockAccessTokens?.let { accessTokens ->
|
||||
GetBlockCredentials(
|
||||
xrp = GetBlockAccessToken(jsonRpc = accessTokens.xrp?.jsonRPC),
|
||||
cardano = GetBlockAccessToken(rosetta = accessTokens.cardano?.rosetta),
|
||||
avalanche = GetBlockAccessToken(jsonRpc = accessTokens.avalanche?.jsonRPC),
|
||||
eth = GetBlockAccessToken(jsonRpc = accessTokens.eth?.jsonRPC),
|
||||
etc = GetBlockAccessToken(jsonRpc = accessTokens.etc?.jsonRPC),
|
||||
fantom = GetBlockAccessToken(jsonRpc = accessTokens.fantom?.jsonRPC),
|
||||
rsk = GetBlockAccessToken(jsonRpc = accessTokens.rsk?.jsonRPC),
|
||||
bsc = GetBlockAccessToken(jsonRpc = accessTokens.bsc?.jsonRPC),
|
||||
polygon = GetBlockAccessToken(jsonRpc = accessTokens.polygon?.jsonRPC),
|
||||
gnosis = GetBlockAccessToken(jsonRpc = accessTokens.gnosis?.jsonRPC),
|
||||
cronos = GetBlockAccessToken(jsonRpc = accessTokens.cronos?.jsonRPC),
|
||||
solana = GetBlockAccessToken(jsonRpc = accessTokens.solana?.jsonRPC),
|
||||
ton = GetBlockAccessToken(jsonRpc = accessTokens.ton?.jsonRPC),
|
||||
tron = GetBlockAccessToken(rest = accessTokens.tron?.rest),
|
||||
cosmos = GetBlockAccessToken(rest = accessTokens.cosmos?.rest),
|
||||
near = GetBlockAccessToken(jsonRpc = accessTokens.near?.jsonRPC),
|
||||
aptos = GetBlockAccessToken(rest = accessTokens.aptos?.rest),
|
||||
dogecoin = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.dogecoin?.jsonRPC,
|
||||
blockBookRest = accessTokens.dogecoin?.blockBookRest,
|
||||
),
|
||||
litecoin = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.litecoin?.jsonRPC,
|
||||
blockBookRest = accessTokens.litecoin?.blockBookRest,
|
||||
),
|
||||
dash = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.dash?.jsonRPC,
|
||||
blockBookRest = accessTokens.dash?.blockBookRest,
|
||||
),
|
||||
bitcoin = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.bitcoin?.jsonRPC,
|
||||
blockBookRest = accessTokens.bitcoin?.blockBookRest,
|
||||
),
|
||||
algorand = GetBlockAccessToken(rest = accessTokens.algorand?.rest),
|
||||
zkSyncEra = GetBlockAccessToken(rest = accessTokens.zksync?.jsonRPC),
|
||||
polygonZkEvm = GetBlockAccessToken(rest = accessTokens.polygonZkevm?.jsonRPC),
|
||||
base = GetBlockAccessToken(rest = accessTokens.base?.jsonRPC),
|
||||
blast = GetBlockAccessToken(jsonRpc = accessTokens.blast?.jsonRPC),
|
||||
filecoin = GetBlockAccessToken(jsonRpc = accessTokens.filecoin?.jsonRPC),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.datasource.config
|
||||
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.config.models.ConfigModel
|
||||
import com.tangem.datasource.config.models.ConfigValueModel
|
||||
import com.tangem.datasource.config.models.FeatureModel
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class FeaturesLocalLoader(
|
||||
private val assetLoader: AssetLoader,
|
||||
buildEnvironment: String,
|
||||
) : Loader<ConfigModel> {
|
||||
|
||||
private val featuresName = "features_$buildEnvironment"
|
||||
private val configValuesName = "tangem-app-config/config_$buildEnvironment"
|
||||
|
||||
override suspend fun load(onComplete: (ConfigModel) -> Unit) {
|
||||
ConfigModel(
|
||||
features = assetLoader.load<FeatureModel>(fileName = featuresName),
|
||||
configValues = assetLoader.load<ConfigValueModel>(fileName = configValuesName),
|
||||
).also(onComplete)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package com.tangem.datasource.config
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface Loader<T> {
|
||||
suspend fun load(onComplete: (T) -> Unit)
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.datasource.config.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
sealed interface ChatConfig
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SprinklrConfig(
|
||||
@Json(name = "appID") val appId: String,
|
||||
@Json(name = "apiKey") val apiKey: String,
|
||||
@Json(name = "environment") val environment: String,
|
||||
) : ChatConfig
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.tangem.datasource.config.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ExpressModel(
|
||||
@Json(name = "apiKey")
|
||||
val apiKey: String,
|
||||
@Json(name = "signVerifierPublicKey")
|
||||
val signVerifierPublicKey: String,
|
||||
)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.tangem.datasource.config.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TonCenterKeys(
|
||||
@Json(name = "mainnet")
|
||||
val mainnet: String,
|
||||
@Json(name = "testnet")
|
||||
val testnet: String,
|
||||
)
|
||||
|
|
@ -5,10 +5,10 @@ import com.tangem.crypto.CryptoUtils
|
|||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
|
||||
internal class Sha256SignatureVerifier(
|
||||
private val configManager: ConfigManager,
|
||||
private val environmentConfigStorage: EnvironmentConfigStorage,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
) : DataSignatureVerifier {
|
||||
|
||||
|
|
@ -24,8 +24,8 @@ internal class Sha256SignatureVerifier(
|
|||
private fun getPubKey(): String? {
|
||||
val expressConfig = apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.Express)
|
||||
return when (expressConfig.environment) {
|
||||
ApiEnvironment.PROD -> configManager.config.express?.signVerifierPublicKey
|
||||
else -> configManager.config.devExpress?.signVerifierPublicKey
|
||||
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().express?.signVerifierPublicKey
|
||||
else -> environmentConfigStorage.getConfigSync().devExpress?.signVerifierPublicKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import com.tangem.datasource.api.common.config.ApiConfig
|
|||
import com.tangem.datasource.api.common.config.Express
|
||||
import com.tangem.datasource.api.common.config.StakeKit
|
||||
import com.tangem.datasource.api.common.config.TangemTech
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.lib.auth.ExpressAuthProvider
|
||||
import com.tangem.lib.auth.StakeKitAuthProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
|
|
@ -21,11 +21,11 @@ internal object ApiConfigsModule {
|
|||
@Provides
|
||||
@IntoSet
|
||||
fun provideExpressConfig(
|
||||
configManager: ConfigManager,
|
||||
environmentConfigStorage: EnvironmentConfigStorage,
|
||||
expressAuthProvider: ExpressAuthProvider,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
): ApiConfig {
|
||||
return Express(configManager, expressAuthProvider, appVersionProvider)
|
||||
return Express(environmentConfigStorage, expressAuthProvider, appVersionProvider)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.config.ConfigManagerImpl
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ConfigModule {
|
||||
|
||||
@Binds
|
||||
fun bindConfigManager(configManager: ConfigManagerImpl): ConfigManager
|
||||
}
|
||||
|
|
@ -4,11 +4,11 @@ import com.squareup.moshi.Moshi
|
|||
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.datasource.api.common.adapter.*
|
||||
import com.tangem.datasource.api.common.adapter.BigDecimalAdapter
|
||||
import com.tangem.datasource.api.common.adapter.DateTimeAdapter
|
||||
import com.tangem.datasource.api.common.adapter.LocalDateAdapter
|
||||
import com.tangem.datasource.config.models.ProviderModel
|
||||
import com.tangem.datasource.api.common.adapter.addStakeKitEnumFallbackAdapters
|
||||
import com.tangem.datasource.local.config.providers.models.ProviderModel
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.datasource.api.common.config.managers.ProdApiConfigsManager
|
|||
import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.markets.TangemTechMarketsApi
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApiV2
|
||||
|
|
@ -94,6 +95,27 @@ internal object NetworkModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
appLogsStore: AppLogsStore,
|
||||
): OnrampApi {
|
||||
return createApi(
|
||||
id = ApiConfig.ID.Express,
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
clientBuilder = {
|
||||
addInterceptor(
|
||||
NetworkLogsSaveInterceptor(appLogsStore),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTangemTechApi(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.crypto.DataSignatureVerifier
|
||||
import com.tangem.datasource.crypto.Sha256SignatureVerifier
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -17,9 +17,9 @@ internal object SecurityModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideDataSignatureVerifier(
|
||||
configManager: ConfigManager,
|
||||
environmentConfigStorage: EnvironmentConfigStorage,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): DataSignatureVerifier {
|
||||
return Sha256SignatureVerifier(configManager, apiConfigsManager)
|
||||
return Sha256SignatureVerifier(environmentConfigStorage, apiConfigsManager)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.tangem.datasource.local.datastore.RuntimeDataStore
|
||||
import com.tangem.datasource.local.token.DefaultStakingYieldsStore
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import dagger.Module
|
||||
|
|
@ -16,6 +15,6 @@ internal object StakingTokensStoreModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideStakingTokensStore(): StakingYieldsStore {
|
||||
return DefaultStakingYieldsStore(dataStore = RuntimeDataStore())
|
||||
return DefaultStakingYieldsStore()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.local.testnet.DefaultTestnetTokensStorage
|
||||
import com.tangem.datasource.local.testnet.TestnetTokensStorage
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object TestnetTokensStorageModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesTestnetTokensStorage(assetLoader: AssetLoader): TestnetTokensStorage {
|
||||
return DefaultTestnetTokensStorage(assetLoader)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.datasource.di.local.config
|
||||
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.local.config.environment.DefaultEnvironmentConfigStorage
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfig
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.datasource.local.config.providers.BlockchainProvidersStorage
|
||||
import com.tangem.datasource.local.config.providers.DefaultBlockchainProvidersStorage
|
||||
import com.tangem.datasource.local.config.testnet.DefaultTestnetTokensStorage
|
||||
import com.tangem.datasource.local.config.testnet.TestnetTokensStorage
|
||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||
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 ConfigModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideEnvironmentConfigStorage(assetLoader: AssetLoader): EnvironmentConfigStorage {
|
||||
return DefaultEnvironmentConfigStorage(
|
||||
assetLoader = assetLoader,
|
||||
environmentConfigStore = RuntimeStateStore(defaultValue = EnvironmentConfig()),
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesTestnetTokensStorage(assetLoader: AssetLoader): TestnetTokensStorage {
|
||||
return DefaultTestnetTokensStorage(assetLoader)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideProvidersOrderConfigStorage(assetLoader: AssetLoader): BlockchainProvidersStorage {
|
||||
return DefaultBlockchainProvidersStorage(
|
||||
assetLoader = assetLoader,
|
||||
runtimeStateStore = RuntimeStateStore(defaultValue = emptyMap()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.datasource.local.config.environment
|
||||
|
||||
import com.tangem.datasource.BuildConfig
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.local.config.environment.converter.EnvironmentConfigConverter
|
||||
import com.tangem.datasource.local.config.environment.models.EnvironmentConfigModel
|
||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Default implementation for storing [EnvironmentConfig]
|
||||
*
|
||||
* @property assetLoader asset loader
|
||||
* @property environmentConfigStore config store
|
||||
*/
|
||||
internal class DefaultEnvironmentConfigStorage(
|
||||
private val assetLoader: AssetLoader,
|
||||
private val environmentConfigStore: RuntimeStateStore<EnvironmentConfig>,
|
||||
) : EnvironmentConfigStorage {
|
||||
|
||||
override suspend fun initialize(): EnvironmentConfig {
|
||||
val environmentConfigModel = assetLoader.load<EnvironmentConfigModel>(fileName = CONFIG_FILE_NAME)
|
||||
?: return environmentConfigStore.get().value
|
||||
|
||||
val config = EnvironmentConfigConverter.convert(value = environmentConfigModel)
|
||||
environmentConfigStore.store(value = config)
|
||||
|
||||
Timber.i("Config [$CONFIG_FILE_NAME] loaded successfully")
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
override fun getConfig(): Flow<EnvironmentConfig> = environmentConfigStore.get()
|
||||
|
||||
override fun getConfigSync(): EnvironmentConfig = environmentConfigStore.get().value
|
||||
|
||||
private companion object {
|
||||
const val CONFIG_FILE_NAME = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,17 @@
|
|||
package com.tangem.datasource.config.models
|
||||
package com.tangem.datasource.local.config.environment
|
||||
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.datasource.local.config.environment.models.ExpressModel
|
||||
|
||||
data class Config(
|
||||
val coinMarketCapKey: String = "f6622117-c043-47a0-8975-9d673ce484de",
|
||||
data class EnvironmentConfig(
|
||||
val moonPayApiKey: String = "pk_test_kc90oYTANy7UQdBavDKGfL4K9l6VEPE",
|
||||
val moonPayApiSecretKey: String = "sk_test_V8w4M19LbDjjYOt170s0tGuvXAgyEb1C",
|
||||
val mercuryoWidgetId: String = "",
|
||||
val mercuryoSecret: String = "",
|
||||
val amplitudeApiKey: String = "",
|
||||
val blockchainSdkConfig: BlockchainSdkConfig = BlockchainSdkConfig(),
|
||||
val isTopUpEnabled: Boolean = false,
|
||||
@Deprecated("Not relevant since version 3.23")
|
||||
val isCreatingTwinCardsAllowed: Boolean = false,
|
||||
val sprinklr: SprinklrConfig? = null,
|
||||
val walletConnectProjectId: String = "",
|
||||
val tangemComAuthorization: String? = null,
|
||||
val express: ExpressModel? = null,
|
||||
val devExpress: ExpressModel? = null,
|
||||
val stakeKitApiKey: String? = null,
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.datasource.local.config.environment
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Storage for [EnvironmentConfig]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface EnvironmentConfigStorage {
|
||||
|
||||
/** Initialize and return [EnvironmentConfig] */
|
||||
suspend fun initialize(): EnvironmentConfig
|
||||
|
||||
/** Get [EnvironmentConfig] as [Flow] */
|
||||
fun getConfig(): Flow<EnvironmentConfig>
|
||||
|
||||
/** Get [EnvironmentConfig] synchronously */
|
||||
fun getConfigSync(): EnvironmentConfig
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.tangem.datasource.local.config.environment.converter
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.datasource.local.config.environment.models.EnvironmentConfigModel
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
/**
|
||||
* Converts [EnvironmentConfigModel] to [BlockchainSdkConfig]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object BlockchainSDKConfigConverter : Converter<EnvironmentConfigModel, BlockchainSdkConfig> {
|
||||
|
||||
override fun convert(value: EnvironmentConfigModel): BlockchainSdkConfig {
|
||||
return BlockchainSdkConfig(
|
||||
blockchairCredentials = BlockchairCredentials(
|
||||
apiKey = value.blockchairApiKeys,
|
||||
authToken = value.blockchairAuthorizationToken,
|
||||
),
|
||||
blockcypherTokens = value.blockcypherTokens,
|
||||
quickNodeSolanaCredentials = QuickNodeCredentials(
|
||||
apiKey = value.quiknodeApiKey,
|
||||
subdomain = value.quiknodeSubdomain,
|
||||
),
|
||||
quickNodeBscCredentials = QuickNodeCredentials(
|
||||
apiKey = value.bscQuiknodeApiKey,
|
||||
subdomain = value.bscQuiknodeSubdomain,
|
||||
),
|
||||
infuraProjectId = value.infuraProjectId,
|
||||
tronGridApiKey = value.tronGridApiKey,
|
||||
nowNodeCredentials = NowNodeCredentials(value.nowNodesApiKey),
|
||||
getBlockCredentials = createGetBlockCredentials(value),
|
||||
kaspaSecondaryApiUrl = value.kaspaSecondaryApiUrl,
|
||||
tonCenterCredentials = TonCenterCredentials(
|
||||
mainnetApiKey = value.tonCenterKeys.mainnet,
|
||||
testnetApiKey = value.tonCenterKeys.testnet,
|
||||
),
|
||||
chiaFireAcademyApiKey = value.chiaFireAcademyApiKey,
|
||||
chiaTangemApiKey = value.chiaTangemApiKey,
|
||||
hederaArkhiaApiKey = value.hederaArkhiaKey,
|
||||
polygonScanApiKey = value.polygonScanApiKey,
|
||||
bittensorDwellirApiKey = value.bittensorDwellirApiKey,
|
||||
bittensorOnfinalityApiKey = value.bittensorOnfinalityKey,
|
||||
koinosProApiKey = value.koinosProApiKey,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createGetBlockCredentials(configValues: EnvironmentConfigModel): GetBlockCredentials? {
|
||||
return configValues.getBlockAccessTokens?.let { accessTokens ->
|
||||
GetBlockCredentials(
|
||||
xrp = GetBlockAccessToken(jsonRpc = accessTokens.xrp?.jsonRPC),
|
||||
cardano = GetBlockAccessToken(rosetta = accessTokens.cardano?.rosetta),
|
||||
avalanche = GetBlockAccessToken(jsonRpc = accessTokens.avalanche?.jsonRPC),
|
||||
eth = GetBlockAccessToken(jsonRpc = accessTokens.eth?.jsonRPC),
|
||||
etc = GetBlockAccessToken(jsonRpc = accessTokens.etc?.jsonRPC),
|
||||
fantom = GetBlockAccessToken(jsonRpc = accessTokens.fantom?.jsonRPC),
|
||||
rsk = GetBlockAccessToken(jsonRpc = accessTokens.rsk?.jsonRPC),
|
||||
bsc = GetBlockAccessToken(jsonRpc = accessTokens.bsc?.jsonRPC),
|
||||
polygon = GetBlockAccessToken(jsonRpc = accessTokens.polygon?.jsonRPC),
|
||||
gnosis = GetBlockAccessToken(jsonRpc = accessTokens.gnosis?.jsonRPC),
|
||||
cronos = GetBlockAccessToken(jsonRpc = accessTokens.cronos?.jsonRPC),
|
||||
solana = GetBlockAccessToken(jsonRpc = accessTokens.solana?.jsonRPC),
|
||||
ton = GetBlockAccessToken(jsonRpc = accessTokens.ton?.jsonRPC),
|
||||
tron = GetBlockAccessToken(rest = accessTokens.tron?.rest),
|
||||
cosmos = GetBlockAccessToken(rest = accessTokens.cosmos?.rest),
|
||||
near = GetBlockAccessToken(jsonRpc = accessTokens.near?.jsonRPC),
|
||||
aptos = GetBlockAccessToken(rest = accessTokens.aptos?.rest),
|
||||
dogecoin = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.dogecoin?.jsonRPC,
|
||||
blockBookRest = accessTokens.dogecoin?.blockBookRest,
|
||||
),
|
||||
litecoin = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.litecoin?.jsonRPC,
|
||||
blockBookRest = accessTokens.litecoin?.blockBookRest,
|
||||
),
|
||||
dash = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.dash?.jsonRPC,
|
||||
blockBookRest = accessTokens.dash?.blockBookRest,
|
||||
),
|
||||
bitcoin = GetBlockAccessToken(
|
||||
jsonRpc = accessTokens.bitcoin?.jsonRPC,
|
||||
blockBookRest = accessTokens.bitcoin?.blockBookRest,
|
||||
),
|
||||
algorand = GetBlockAccessToken(rest = accessTokens.algorand?.rest),
|
||||
zkSyncEra = GetBlockAccessToken(jsonRpc = accessTokens.zksync?.jsonRPC),
|
||||
polygonZkEvm = GetBlockAccessToken(jsonRpc = accessTokens.polygonZkevm?.jsonRPC),
|
||||
base = GetBlockAccessToken(jsonRpc = accessTokens.base?.jsonRPC),
|
||||
blast = GetBlockAccessToken(jsonRpc = accessTokens.blast?.jsonRPC),
|
||||
filecoin = GetBlockAccessToken(jsonRpc = accessTokens.filecoin?.jsonRPC),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.datasource.local.config.environment.converter
|
||||
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfig
|
||||
import com.tangem.datasource.local.config.environment.models.EnvironmentConfigModel
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
/**
|
||||
* Converter from [EnvironmentConfigModel] to [EnvironmentConfig]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object EnvironmentConfigConverter : Converter<EnvironmentConfigModel, EnvironmentConfig> {
|
||||
|
||||
override fun convert(value: EnvironmentConfigModel): EnvironmentConfig {
|
||||
return EnvironmentConfig(
|
||||
moonPayApiKey = value.moonPayApiKey,
|
||||
moonPayApiSecretKey = value.moonPayApiSecretKey,
|
||||
mercuryoWidgetId = value.mercuryoWidgetId,
|
||||
mercuryoSecret = value.mercuryoSecret,
|
||||
blockchainSdkConfig = BlockchainSDKConfigConverter.convert(value = value),
|
||||
amplitudeApiKey = value.amplitudeApiKey,
|
||||
walletConnectProjectId = value.walletConnectProjectId,
|
||||
express = value.express,
|
||||
devExpress = value.devExpress,
|
||||
stakeKitApiKey = value.stakeKitApiKey,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +1,37 @@
|
|||
package com.tangem.datasource.config.models
|
||||
package com.tangem.datasource.local.config.environment.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
|
||||
// TODO remove
|
||||
class FeatureModel(
|
||||
val isTopUpEnabled: Boolean,
|
||||
val isCreatingTwinCardsAllowed: Boolean,
|
||||
)
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
class ConfigValueModel(
|
||||
val coinMarketCapKey: String,
|
||||
val mercuryoWidgetId: String,
|
||||
val mercuryoSecret: String,
|
||||
val moonPayApiKey: String,
|
||||
val moonPayApiSecretKey: String,
|
||||
val blockchairApiKeys: List<String>,
|
||||
val blockchairAuthorizationToken: String?,
|
||||
val quiknodeSubdomain: String,
|
||||
val quiknodeApiKey: String,
|
||||
val bscQuiknodeSubdomain: String,
|
||||
val bscQuiknodeApiKey: String,
|
||||
val nowNodesApiKey: String,
|
||||
@JsonClass(generateAdapter = true)
|
||||
class EnvironmentConfigModel(
|
||||
@Json(name = "mercuryoWidgetId") val mercuryoWidgetId: String,
|
||||
@Json(name = "mercuryoSecret") val mercuryoSecret: String,
|
||||
@Json(name = "moonPayApiKey") val moonPayApiKey: String,
|
||||
@Json(name = "moonPayApiSecretKey") val moonPayApiSecretKey: String,
|
||||
@Json(name = "blockchairApiKeys") val blockchairApiKeys: List<String>,
|
||||
@Json(name = "blockchairAuthorizationToken") val blockchairAuthorizationToken: String?,
|
||||
@Json(name = "quiknodeSubdomain") val quiknodeSubdomain: String,
|
||||
@Json(name = "quiknodeApiKey") val quiknodeApiKey: String,
|
||||
@Json(name = "bscQuiknodeSubdomain") val bscQuiknodeSubdomain: String,
|
||||
@Json(name = "bscQuiknodeApiKey") val bscQuiknodeApiKey: String,
|
||||
@Json(name = "nowNodesApiKey") val nowNodesApiKey: String,
|
||||
@Json(name = "getBlockAccessTokens") val getBlockAccessTokens: GetBlockAccessTokens?,
|
||||
@Json(name = "tonCenterApiKey") val tonCenterKeys: TonCenterKeys,
|
||||
val blockcypherTokens: Set<String>?,
|
||||
val infuraProjectId: String?,
|
||||
val sprinklr: SprinklrConfig?,
|
||||
val tronGridApiKey: String,
|
||||
val amplitudeApiKey: String,
|
||||
val kaspaSecondaryApiUrl: String,
|
||||
val walletConnectProjectId: String,
|
||||
val tangemComAuthorization: String?,
|
||||
val chiaFireAcademyApiKey: String?,
|
||||
val chiaTangemApiKey: String?,
|
||||
val devExpress: ExpressModel?,
|
||||
val express: ExpressModel?,
|
||||
@Json(name = "blockcypherTokens") val blockcypherTokens: Set<String>?,
|
||||
@Json(name = "infuraProjectId") val infuraProjectId: String?,
|
||||
@Json(name = "tronGridApiKey") val tronGridApiKey: String,
|
||||
@Json(name = "amplitudeApiKey") val amplitudeApiKey: String,
|
||||
@Json(name = "kaspaSecondaryApiUrl") val kaspaSecondaryApiUrl: String,
|
||||
@Json(name = "walletConnectProjectId") val walletConnectProjectId: String,
|
||||
@Json(name = "chiaFireAcademyApiKey") val chiaFireAcademyApiKey: String?,
|
||||
@Json(name = "chiaTangemApiKey") val chiaTangemApiKey: String?,
|
||||
@Json(name = "devExpress") val devExpress: ExpressModel?,
|
||||
@Json(name = "express") val express: ExpressModel?,
|
||||
@Json(name = "hederaArkhiaKey") val hederaArkhiaKey: String?,
|
||||
val polygonScanApiKey: String?,
|
||||
val stakeKitApiKey: String?,
|
||||
@Json(name = "polygonScanApiKey") val polygonScanApiKey: String?,
|
||||
@Json(name = "stakeKitApiKey") val stakeKitApiKey: String?,
|
||||
@Json(name = "bittensorDwellirKey") val bittensorDwellirApiKey: String?,
|
||||
@Json(name = "bittensorOnfinalityKey") val bittensorOnfinalityKey: String?,
|
||||
@Json(name = "koinosProApiKey") val koinosProApiKey: String?,
|
||||
|
|
@ -80,6 +68,12 @@ data class GetBlockAccessTokens(
|
|||
@Json(name = "filecoin") val filecoin: GetBlockToken?,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TonCenterKeys(
|
||||
@Json(name = "mainnet") val mainnet: String,
|
||||
@Json(name = "testnet") val testnet: String,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GetBlockToken(
|
||||
@Json(name = "jsonRpc") val jsonRPC: String?,
|
||||
|
|
@ -88,11 +82,10 @@ data class GetBlockToken(
|
|||
@Json(name = "rosetta") val rosetta: String?,
|
||||
)
|
||||
|
||||
class ConfigModel(
|
||||
val features: FeatureModel?,
|
||||
val configValues: ConfigValueModel?,
|
||||
) {
|
||||
companion object {
|
||||
fun empty(): ConfigModel = ConfigModel(null, null)
|
||||
}
|
||||
}
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ExpressModel(
|
||||
@Json(name = "apiKey")
|
||||
val apiKey: String,
|
||||
@Json(name = "signVerifierPublicKey")
|
||||
val signVerifierPublicKey: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.datasource.local.config.providers
|
||||
|
||||
import com.tangem.datasource.local.config.providers.models.ProviderModel
|
||||
|
||||
/**
|
||||
* Blockchain providers storage
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface BlockchainProvidersStorage {
|
||||
|
||||
/** Get config */
|
||||
suspend fun getConfigSync(): Map<String, List<ProviderModel>>
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.datasource.local.config.providers
|
||||
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.local.config.providers.models.ProviderModel
|
||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||
|
||||
/**
|
||||
* Default blockchain providers storage
|
||||
*
|
||||
* @property assetLoader asset loader
|
||||
* @property runtimeStateStore runtime state store
|
||||
*/
|
||||
internal class DefaultBlockchainProvidersStorage(
|
||||
private val assetLoader: AssetLoader,
|
||||
private val runtimeStateStore: RuntimeStateStore<Map<String, List<ProviderModel>>>,
|
||||
) : BlockchainProvidersStorage {
|
||||
|
||||
override suspend fun getConfigSync(): Map<String, List<ProviderModel>> {
|
||||
val cachedData = runtimeStateStore.get().value
|
||||
|
||||
if (cachedData.isNotEmpty()) return cachedData
|
||||
|
||||
val config = assetLoader.load<Map<String, List<ProviderModel>>>(fileName = PROVIDER_TYPES_FILE_NAME).orEmpty()
|
||||
|
||||
runtimeStateStore.store(value = config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PROVIDER_TYPES_FILE_NAME = "tangem-app-config/providers_order"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.datasource.config.models
|
||||
package com.tangem.datasource.local.config.providers.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.datasource.local.testnet
|
||||
package com.tangem.datasource.local.config.testnet
|
||||
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.local.testnet.models.TestnetTokensConfig
|
||||
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
|
||||
|
||||
/**
|
||||
* Default implementation for storing testnet tokens data
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.datasource.local.testnet
|
||||
package com.tangem.datasource.local.config.testnet
|
||||
|
||||
import com.tangem.datasource.local.testnet.models.TestnetTokensConfig
|
||||
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
|
||||
|
||||
/**
|
||||
* Storage of testnet tokens data
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.datasource.local.testnet.models
|
||||
package com.tangem.datasource.local.config.testnet.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ import com.squareup.moshi.Json
|
|||
*
|
||||
* @property tokens testnet tokens list
|
||||
*/
|
||||
// TODO: use CoinsResponse
|
||||
data class TestnetTokensConfig(
|
||||
@Json(name = "coins") val tokens: List<Token>,
|
||||
) {
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
package com.tangem.datasource.local.datastore
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.tangem.datasource.files.FileReader
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.datasource.local.datastore.utils.Trigger
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
|
||||
@Deprecated("Use shared preferences data store instead")
|
||||
internal class FileDataStore<Value : Any>(
|
||||
private val fileReader: FileReader,
|
||||
private val adapter: JsonAdapter<Value>,
|
||||
) : StringKeyDataStore<Value> {
|
||||
|
||||
private val mutex = Mutex()
|
||||
private val writeTrigger = Trigger()
|
||||
override suspend fun isEmpty(): Boolean {
|
||||
val e = NotImplementedError("`isEmpty()` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
override suspend fun contains(key: String): Boolean = getSyncOrNull(key) != null
|
||||
|
||||
override fun get(key: String): Flow<Value> {
|
||||
return writeTrigger
|
||||
.map {
|
||||
mutex.withLock {
|
||||
getInternal(key)
|
||||
}
|
||||
}
|
||||
.filterNotNull()
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override fun getAll(): Flow<List<Value>> {
|
||||
val e = NotImplementedError("`getAll()` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(key: String): Value? {
|
||||
return getInternal(key)
|
||||
}
|
||||
|
||||
override suspend fun getAllSyncOrNull(): List<Value>? {
|
||||
val e = NotImplementedError("`getAllSyncOrNull()` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
override suspend fun store(key: String, value: Value) {
|
||||
try {
|
||||
mutex.withLock {
|
||||
val json = adapter.toJson(value)
|
||||
|
||||
fileReader.rewriteFile(json, key)
|
||||
writeTrigger.trigger()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to write file: $key")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun store(values: Map<String, Value>) {
|
||||
values.forEach { (key, item) ->
|
||||
store(key, item)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun remove(key: String) {
|
||||
fileReader.removeFile(key)
|
||||
writeTrigger.trigger()
|
||||
}
|
||||
|
||||
override suspend fun remove(keys: Collection<String>) {
|
||||
val e = NotImplementedError("`remove(keys)` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
val e = NotImplementedError("`clear()` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
private fun getInternal(fileName: String): Value? {
|
||||
return try {
|
||||
val json = fileReader.readFile(fileName)
|
||||
|
||||
adapter.fromJson(json)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to read file: $fileName")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.datasource.local.datastore
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Runtime store
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface RuntimeStateStore<T> {
|
||||
|
||||
/** Get flow of elements [T] */
|
||||
fun get(): StateFlow<T>
|
||||
|
||||
/** Store [value] */
|
||||
suspend fun store(value: T)
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Create [RuntimeStateStore]
|
||||
*
|
||||
* @param T type of stored value
|
||||
* @param defaultValue default value
|
||||
*/
|
||||
operator fun <T> invoke(defaultValue: T): RuntimeStateStore<T> = object : RuntimeStateStore<T> {
|
||||
private val flow = MutableStateFlow(value = defaultValue)
|
||||
|
||||
override fun get(): StateFlow<T> = flow
|
||||
|
||||
override suspend fun store(value: T) {
|
||||
flow.value = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package com.tangem.datasource.local.datastore.utils
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
/**
|
||||
* Represents a trigger mechanism to emit values on-demand.
|
||||
*
|
||||
* This class provides a mechanism to trigger emissions via the [trigger] method.
|
||||
*
|
||||
* @property triggerFlow The internal flow that gets toggled to trigger emissions.
|
||||
*/
|
||||
internal class Trigger(
|
||||
private val triggerFlow: MutableStateFlow<Boolean> = MutableStateFlow(value = false),
|
||||
) : Flow<Unit> {
|
||||
|
||||
/**
|
||||
* Collects values emitted by this flow.
|
||||
*
|
||||
* Overrides the default collection mechanism to emit a [Unit] value whenever [triggerFlow] changes.
|
||||
*
|
||||
* @param collector The collector responsible for handling emitted values.
|
||||
*/
|
||||
override suspend fun collect(collector: FlowCollector<Unit>): Nothing {
|
||||
triggerFlow.collect { collector.emit(Unit) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an emission.
|
||||
*/
|
||||
fun trigger() {
|
||||
triggerFlow.value = !triggerFlow.value
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,9 @@ class AppLogsStore @Inject constructor(
|
|||
private fun launchWithLock(callback: () -> Unit) {
|
||||
scope.launch {
|
||||
mutex.withLock {
|
||||
callback()
|
||||
runCatching {
|
||||
callback()
|
||||
}.onFailure(Timber::e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
|||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
|
|
@ -29,9 +29,13 @@ internal class DefaultStakingBalanceStore(
|
|||
}
|
||||
}
|
||||
|
||||
override fun get(userWalletId: UserWalletId, address: String, integrationId: String): Flow<YieldBalanceWrapperDTO> {
|
||||
override fun get(
|
||||
userWalletId: UserWalletId,
|
||||
address: String,
|
||||
integrationId: String,
|
||||
): Flow<YieldBalanceWrapperDTO?> {
|
||||
return dataStore.get(userWalletId.stringValue)
|
||||
.mapNotNull { balances ->
|
||||
.map { balances ->
|
||||
balances.firstOrNull { it.integrationId == integrationId && it.addresses.address == address }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.domain.staking.model.StakingTokenWithYield
|
||||
|
||||
internal class DefaultStakingTokensStore(
|
||||
private val dataStore: StringKeyDataStore<List<StakingTokenWithYield>>,
|
||||
) : StakingTokensStore {
|
||||
|
||||
override suspend fun getSyncOrNull(): List<StakingTokenWithYield>? {
|
||||
return dataStore.getSyncOrNull(STAKING_TOKENS_KEY)
|
||||
}
|
||||
|
||||
override suspend fun store(items: List<StakingTokenWithYield>) {
|
||||
dataStore.store(STAKING_TOKENS_KEY, items)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STAKING_TOKENS_KEY = "STAKING_TOKENS_KEY"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,16 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
|
||||
internal class DefaultStakingYieldsStore(
|
||||
private val dataStore: StringKeyDataStore<List<YieldDTO>>,
|
||||
) : StakingYieldsStore {
|
||||
internal class DefaultStakingYieldsStore : StakingYieldsStore {
|
||||
|
||||
override suspend fun getSyncOrNull(): List<YieldDTO>? {
|
||||
return dataStore.getSyncOrNull(STAKING_YIELDS_KEY)
|
||||
private var yields = mutableListOf<YieldDTO>()
|
||||
|
||||
override fun get(): List<YieldDTO> {
|
||||
return yields
|
||||
}
|
||||
|
||||
override suspend fun store(items: List<YieldDTO>) {
|
||||
dataStore.store(STAKING_YIELDS_KEY, items)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STAKING_YIELDS_KEY = "STAKING_YIELDS_KEY"
|
||||
override fun store(items: List<YieldDTO>) {
|
||||
yields = items.toMutableList()
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ interface StakingBalanceStore {
|
|||
|
||||
suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>)
|
||||
|
||||
fun get(userWalletId: UserWalletId, address: String, integrationId: String): Flow<YieldBalanceWrapperDTO>
|
||||
fun get(userWalletId: UserWalletId, address: String, integrationId: String): Flow<YieldBalanceWrapperDTO?>
|
||||
|
||||
suspend fun getSyncOrNull(
|
||||
userWalletId: UserWalletId,
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import com.tangem.domain.staking.model.StakingTokenWithYield
|
||||
|
||||
interface StakingTokensStore {
|
||||
|
||||
suspend fun getSyncOrNull(): List<StakingTokenWithYield>?
|
||||
|
||||
suspend fun store(items: List<StakingTokenWithYield>)
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
|
|||
|
||||
interface StakingYieldsStore {
|
||||
|
||||
suspend fun getSyncOrNull(): List<YieldDTO>?
|
||||
fun get(): List<YieldDTO>
|
||||
|
||||
suspend fun store(items: List<YieldDTO>)
|
||||
fun store(items: List<YieldDTO>)
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package com.tangem.datasource.api.common.config.managers
|
||||
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.config.Loader
|
||||
import com.tangem.datasource.config.models.Config
|
||||
import com.tangem.datasource.config.models.ConfigModel
|
||||
import com.tangem.datasource.config.models.ExpressModel
|
||||
|
||||
/**
|
||||
* Mock [ConfigManager] implementation for [ProdApiConfigsManagerTest]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class MockConfigManager : ConfigManager {
|
||||
|
||||
override val config = Config(
|
||||
express = ExpressModel(apiKey = ProdApiConfigsManagerTest.EXPRESS_API_KEY, signVerifierPublicKey = ""),
|
||||
devExpress = ExpressModel(apiKey = ProdApiConfigsManagerTest.EXPRESS_DEV_API_KEY, signVerifierPublicKey = ""),
|
||||
)
|
||||
|
||||
override suspend fun load(configLoader: Loader<ConfigModel>, onComplete: ((config: Config) -> Unit)?) = Unit
|
||||
override fun turnOff(name: String) = Unit
|
||||
override fun resetToDefault(name: String) = Unit
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.datasource.api.common.config.managers
|
||||
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfig
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.datasource.local.config.environment.models.ExpressModel
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
/**
|
||||
* Mock [EnvironmentConfigStorage] implementation for [ProdApiConfigsManagerTest]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage {
|
||||
|
||||
private val environmentConfig = EnvironmentConfig(
|
||||
express = ExpressModel(apiKey = EXPRESS_API_KEY, signVerifierPublicKey = "vocibus"),
|
||||
devExpress = ExpressModel(apiKey = EXPRESS_DEV_API_KEY, signVerifierPublicKey = "pellentesque"),
|
||||
)
|
||||
|
||||
override suspend fun initialize() = environmentConfig
|
||||
override fun getConfig() = flowOf(environmentConfig)
|
||||
override fun getConfigSync() = environmentConfig
|
||||
|
||||
companion object {
|
||||
const val EXPRESS_API_KEY = "express_api_key"
|
||||
const val EXPRESS_DEV_API_KEY = "express_dev_api_key"
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ import org.junit.Test
|
|||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
private val configManager = MockConfigManager()
|
||||
private val configManager = MockEnvironmentConfigStorage()
|
||||
private val appVersionProvider = mockk<AppVersionProvider>()
|
||||
private val expressAuthProvider = mockk<ExpressAuthProvider>()
|
||||
private val stakeKitAuthProvider = mockk<StakeKitAuthProvider>()
|
||||
|
|
@ -67,8 +67,6 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
|
|||
const val EXPRESS_USER_ID = "express_user_id"
|
||||
const val EXPRESS_SESSION_ID = "express_session_id"
|
||||
const val EXPRESS_REF_CODE = "express_ref_code"
|
||||
const val EXPRESS_API_KEY = "express_api_key"
|
||||
const val EXPRESS_DEV_API_KEY = "express_dev_api_key"
|
||||
const val STAKE_KIT_API_KEY = "stake_kit_api_key"
|
||||
|
||||
@JvmStatic
|
||||
|
|
@ -109,7 +107,11 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
|
|||
},
|
||||
headers = mapOf(
|
||||
"api-key" to Provider {
|
||||
if (environment == ApiEnvironment.PROD) EXPRESS_API_KEY else EXPRESS_DEV_API_KEY
|
||||
if (environment == ApiEnvironment.PROD) {
|
||||
MockEnvironmentConfigStorage.EXPRESS_API_KEY
|
||||
} else {
|
||||
MockEnvironmentConfigStorage.EXPRESS_DEV_API_KEY
|
||||
}
|
||||
},
|
||||
"user-id" to Provider { EXPRESS_USER_ID },
|
||||
"session-id" to Provider { EXPRESS_SESSION_ID },
|
||||
|
|
|
|||
|
|
@ -3,14 +3,6 @@
|
|||
"name": "NEW_CARD_SCANNING_ENABLED",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "LOCAL_USER_LOGS_ENABLED",
|
||||
"version": "5.14.0"
|
||||
},
|
||||
{
|
||||
"name": "GENERATE_XPUB_ENABLED",
|
||||
"version": "5.12.0"
|
||||
},
|
||||
{
|
||||
"name": "WC_SOLANA_TX_SIGN_ENABLED",
|
||||
"version": "undefined"
|
||||
|
|
@ -19,24 +11,16 @@
|
|||
"name": "STAKING_ENABLED",
|
||||
"version": "5.15.0"
|
||||
},
|
||||
{
|
||||
"name": "DETAILS_REDESIGN_ENABLED",
|
||||
"version": "5.13.0"
|
||||
},
|
||||
{
|
||||
"name": "PUSH_NOTIFICATIONS_ENABLED",
|
||||
"version": "5.13.0"
|
||||
},
|
||||
{
|
||||
"name": "MARKETS_ENABLED",
|
||||
"version": "5.15.0"
|
||||
},
|
||||
{
|
||||
"name": "NEW_MANAGE_TOKENS",
|
||||
"version": "5.15.0"
|
||||
},
|
||||
{
|
||||
"name": "IS_ETHEREUM_EIP_1559_ENABLED",
|
||||
"version": "5.17.0"
|
||||
},
|
||||
{
|
||||
"name": "MIGRATE_USER_COUNTRY_CODE_ENABLED",
|
||||
"version": "5.17.0"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ internal class DevFeatureTogglesManager(
|
|||
) : MutableFeatureTogglesManager {
|
||||
|
||||
private var featureTogglesMap: MutableMap<String, Boolean> by Delegates.notNull()
|
||||
private var localFeatureTogglesMap: Map<String, Boolean> by Delegates.notNull()
|
||||
|
||||
override suspend fun init() {
|
||||
localFeatureTogglesStorage.init()
|
||||
|
|
@ -32,8 +33,12 @@ internal class DevFeatureTogglesManager(
|
|||
key = PreferencesKeys.FEATURE_TOGGLES_KEY,
|
||||
) ?: emptyMap()
|
||||
|
||||
featureTogglesMap = localFeatureTogglesStorage.featureToggles
|
||||
val localFeatureToggles = localFeatureTogglesStorage.featureToggles
|
||||
.associateToggles(currentVersion = versionProvider.get().orEmpty())
|
||||
|
||||
localFeatureTogglesMap = localFeatureToggles
|
||||
|
||||
featureTogglesMap = localFeatureToggles
|
||||
.mapValues { resultToggle ->
|
||||
savedFeatureToggles[resultToggle.key] ?: resultToggle.value
|
||||
}
|
||||
|
|
@ -42,16 +47,27 @@ internal class DevFeatureTogglesManager(
|
|||
|
||||
override fun isFeatureEnabled(name: String): Boolean = featureTogglesMap[name] ?: false
|
||||
|
||||
override fun isMatchLocalConfig(): Boolean = featureTogglesMap == localFeatureTogglesMap
|
||||
|
||||
override fun getFeatureToggles(): Map<String, Boolean> = featureTogglesMap
|
||||
|
||||
override suspend fun changeToggle(name: String, isEnabled: Boolean) {
|
||||
featureTogglesMap[name] ?: return
|
||||
featureTogglesMap[name] = isEnabled
|
||||
appPreferencesStore.storeObject(PreferencesKeys.FEATURE_TOGGLES_KEY, featureTogglesMap)
|
||||
appPreferencesStore.storeFeatureToggles(value = featureTogglesMap)
|
||||
}
|
||||
|
||||
override suspend fun recoverLocalConfig() {
|
||||
featureTogglesMap = localFeatureTogglesMap.toMutableMap()
|
||||
appPreferencesStore.storeFeatureToggles(value = localFeatureTogglesMap)
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
|
||||
fun setFeatureToggles(map: MutableMap<String, Boolean>) {
|
||||
featureTogglesMap = map
|
||||
}
|
||||
|
||||
private suspend fun AppPreferencesStore.storeFeatureToggles(value: Map<String, Boolean>) {
|
||||
storeObject(PreferencesKeys.FEATURE_TOGGLES_KEY, value)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,9 +7,15 @@ package com.tangem.core.featuretoggle.manager
|
|||
*/
|
||||
interface MutableFeatureTogglesManager : FeatureTogglesManager {
|
||||
|
||||
/** Check if the current state of the feature toggles matches the local config state. */
|
||||
fun isMatchLocalConfig(): Boolean
|
||||
|
||||
/** Get feature toggles */
|
||||
fun getFeatureToggles(): Map<String, Boolean>
|
||||
|
||||
/** Change availability [isEnabled] of toggle with name [name] */
|
||||
suspend fun changeToggle(name: String, isEnabled: Boolean)
|
||||
|
||||
/** Recover local config state */
|
||||
suspend fun recoverLocalConfig()
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package com.tangem.core.navigation.di
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.core.navigation.email.AndroidEmailSender
|
||||
import com.tangem.core.navigation.email.EmailSender
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.hilt.android.qualifiers.ActivityContext
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ActivityComponent::class)
|
||||
internal object EmailSenderModule {
|
||||
|
||||
@Provides
|
||||
@ActivityScoped
|
||||
fun provideEmailSender(@ActivityContext context: Context): EmailSender {
|
||||
return AndroidEmailSender(context)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package com.tangem.core.navigation.email
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Implementation of email sender for Android
|
||||
*
|
||||
* @property context context
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class AndroidEmailSender(private val context: Context) : EmailSender {
|
||||
|
||||
override fun send(email: EmailSender.Email, onFail: ((Exception) -> Unit)?) {
|
||||
val originalIntent = createEmailShareIntent(email)
|
||||
val emailFilterIntent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"))
|
||||
|
||||
val packageManager = context.packageManager
|
||||
val originalIntentResults = packageManager.queryIntentActivities(originalIntent, 0)
|
||||
val emailFilterIntentResults = packageManager.queryIntentActivities(emailFilterIntent, 0)
|
||||
|
||||
val targetedIntents = originalIntentResults
|
||||
.filter { originalResult ->
|
||||
emailFilterIntentResults.any {
|
||||
originalResult.activityInfo.packageName == it.activityInfo.packageName
|
||||
}
|
||||
}
|
||||
.map {
|
||||
createEmailShareIntent(email).apply { setPackage(it.activityInfo.packageName) }
|
||||
}
|
||||
.toMutableList()
|
||||
|
||||
try {
|
||||
val chooserIntent = Intent.createChooser(targetedIntents.removeAt(0), "Send mail...").apply {
|
||||
putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toTypedArray())
|
||||
}
|
||||
|
||||
ContextCompat.startActivity(context, chooserIntent, null)
|
||||
} catch (ex: Exception) {
|
||||
Timber.e("Failed to send email: $ex")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEmailShareIntent(email: EmailSender.Email): Intent {
|
||||
val builder = ShareCompat.IntentBuilder(context)
|
||||
.setType("message/rfc822")
|
||||
.setEmailTo(arrayOf(email.address))
|
||||
.setSubject(email.subject)
|
||||
.setText(email.message)
|
||||
|
||||
email.attachment?.let {
|
||||
builder.setStream(
|
||||
FileProvider.getUriForFile(context, "${context.packageName}.provider", it),
|
||||
)
|
||||
}
|
||||
|
||||
return builder.intent
|
||||
}
|
||||
}
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
<string name="details_manage_security_access_code">Zugangscode</string>
|
||||
<string name="details_manage_security_access_code_description">Du musst den richtigen Zugangscode eingeben, bevor du die Karte oder Ring scannst.</string>
|
||||
<string name="details_manage_security_long_tap">Langes Tippen</string>
|
||||
<string name="details_manage_security_long_tap_description">Dieser Mechanismus schützt vor Annäherungsangriffen auf eine Karte oder Ring. Es wird eine Verzögerung zwischen dem Empfang und der Ausführung eines Befehls erzwungen. Nach der ersten signierten Transaktion wird dieses Telefon mit der Karte oder Ring verknüpft und die Transaktionen werden sofort signiert</string>
|
||||
<string name="details_manage_security_long_tap_description">Dieser Mechanismus schützt vor Annäherungsangriffen auf eine Karte oder Ring. Es wird eine Verzögerung zwischen dem Empfang und der Ausführung eines Befehls erzwungen. Nach der ersten signierten Transaktion wird dieses Telefon mit der Karte oder Ring verknüpft und die Transaktionen werden sofort signiert.</string>
|
||||
<string name="details_manage_security_passcode">Passcode</string>
|
||||
<string name="details_manage_security_passcode_description">Bevor du einen Befehl ausführst, der eine Änderung des Kartenstatus zur Folge hat, musst du den Passcode eingeben.</string>
|
||||
<string name="details_referral_title">Empfehlungsprogramm</string>
|
||||
|
|
@ -912,7 +912,7 @@
|
|||
<string name="warning_access_denied_message">Verwende %s oder scanne eine Karte oder Ring, um den Zugriff auf deine Wallet freizuschalten.</string>
|
||||
<string name="warning_approval_in_progress_message">Das Genehmigungsverfahren ist derzeit im Gange und wird in Kürze abgeschlossen sein</string>
|
||||
<string name="warning_approval_in_progress_title">Genehmigung läuft</string>
|
||||
<string name="warning_backup_errors_message">Es scheint, dass die Aktivierung der Karte oder des Rings nicht korrekt abgeschlossen wurde. Dies kann an einem Problem mit dem NFC-Modul deines Gerätes oder an einem falschen Tippen der Karte oder Ring auf dein Gerät liegen. Bitte wende dich an unser Support-Team, um Unterstützung zu erhalten.</string>
|
||||
<string name="warning_backup_errors_message">Es scheint, dass die Aktivierung der Karte oder des Rings nicht korrekt abgeschlossen wurde. Dies kann an einem Problem mit dem NFC-Modul deines Gerätes oder an einem falschen Tippen der Karte oder Ring auf dein Gerät liegen. Bitte wende dich an unser Support-Team, um Unterstützung zu erhalten.</string>
|
||||
<string name="warning_backup_errors_title">Aktivierungsfehler</string>
|
||||
<string name="warning_beacon_chain_retirement_content">Laut den Entwicklern des BNB-Netzes wird die Unterstützung für den BEP-2-Standard im Juni 2024 enden. Um den Verlust von Vermögenswerten mit diesem Standard zu vermeiden, konvertiere bitte in den BEP-20 Standard. Nutze gerne unseren Swap-Service, um sie auf das BNB Smart Chain Netzwerk zu übertragen.</string>
|
||||
<string name="warning_beacon_chain_retirement_title">BNB Beacon Chain wird abgeschaltet</string>
|
||||
|
|
@ -925,7 +925,7 @@
|
|||
<string name="warning_button_refresh">Aktualisieren</string>
|
||||
<string name="warning_demo_mode_message">Du befindest sich derzeit im Demo-Modus</string>
|
||||
<string name="warning_demo_mode_title">Demo-Modus aktiv</string>
|
||||
<string name="warning_developer_card_message">Die Karte oder Ring, die du gescannt hast, ist eine Entwicklerkarte. Verwenden diese nicht zur Erstellung Ihrer Wallet.</string>
|
||||
<string name="warning_developer_card_message">Die Karte, die du gescannt hast, ist eine Entwicklerkarte. Verwenden diese nicht zur Erstellung Ihrer Wallet.</string>
|
||||
<string name="warning_developer_card_title">Nicht für Benutzer!</string>
|
||||
<string name="warning_existential_deposit_message">%1$s Netzwerk erfordert eine Mindesteinlage. Wenn dein Konto unter %2$s fällt, wird es deaktiviert und alle verbleibenden Guthaben werden vernichtet.</string>
|
||||
<string name="warning_existential_deposit_title">Netzwerk erfordert eine Mindesteinzahlung</string>
|
||||
|
|
@ -952,7 +952,7 @@
|
|||
<string name="warning_hedera_missing_token_association_message_brief">Dieses Token muss mit deinem Hedera-Konto verknüpft sein, bevor du ihn erhalten kannst.</string>
|
||||
<string name="warning_hedera_missing_token_association_title">Verknüpfe deinen Token</string>
|
||||
<string name="warning_hedera_token_association_not_enough_hbar_message">Nicht genug %s. Lade dein Hedera-Konto auf, um dieses Token zuzuordnen</string>
|
||||
<string name="warning_low_signatures_message">Auf dieser Karte oder Ring oder Ring sind nur noch %s Unterschriften übrig. Du musst dein gesamtes Guthaben abheben.</string>
|
||||
<string name="warning_low_signatures_message">Auf dieser Karte oder Ring sind nur noch %s Unterschriften übrig. Du musst dein gesamtes Guthaben abheben.</string>
|
||||
<string name="warning_low_signatures_title">Geringe Anzahl von Unterschriften</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Token in verschiedenen Netzwerken können unterschiedliche Adressen haben. Überprüfe bei der Überweisung noch einmal, ob deine Adresse mit der des Netzwerks übereinstimmt.</string>
|
||||
<string name="warning_matic_migration_message">MATIC wird auf POL migriert. Es gibt jedoch keine Frist, und MATIC wird noch nicht abgeschafft. Du kannst MATIC-Token weiterhin verwenden oder sie über eien Exchange gegen POL tauschen.</string>
|
||||
|
|
@ -980,7 +980,7 @@
|
|||
<string name="warning_solana_rent_fee_message">Das Solana-Netzwerk erhebt alle 2 Tage eine Miete von %1$s. Konten, die sich die Miete nicht leisten können, werden aus dem Netzwerk gelöscht. Hinterlege deinem Konto mit mehr als %2$s, um es kostenlos zu nutzen.</string>
|
||||
<string name="warning_some_networks_unreachable_message">Einige Netzwerke sind derzeit nicht erreichbar. Bitte versuche es später erneut.</string>
|
||||
<string name="warning_some_networks_unreachable_title">Einige Netzwerke sind nicht erreichbar</string>
|
||||
<string name="warning_testnet_card_message">Dies ist eine Testnet-Karte oder Ring. Sie kann keine Transaktionen verarbeiten und sollte nur zu Test- und Entwicklungszwecken verwendet werden.</string>
|
||||
<string name="warning_testnet_card_message">Dies ist eine Testnet-Karte. Sie kann keine Transaktionen verarbeiten und sollte nur zu Test- und Entwicklungszwecken verwendet werden.</string>
|
||||
<string name="warning_testnet_card_title">Nur für Testzwecke</string>
|
||||
<string name="welcome_interrupted_backup_alert_discard">Verwerfen</string>
|
||||
<string name="welcome_interrupted_backup_alert_message">Du hast eine unterbrochene Sicherung. Möchtest du diese fortsetzen?</string>
|
||||
|
|
|
|||
|
|
@ -34,15 +34,15 @@
|
|||
<string name="balance_hidden_do_not_show_button">No mostrar de nuevo</string>
|
||||
<string name="balance_hidden_got_it_button">Entendido</string>
|
||||
<string name="balance_hidden_title">Los saldos están ocultos</string>
|
||||
<string name="biometric_lockout_permanent_warning_description">Por favor, escanee la tarjeta</string>
|
||||
<string name="biometric_lockout_warning_description">Por favor, inténtelo de nuevo en 30 segundos o escanee la tarjeta</string>
|
||||
<string name="biometric_lockout_permanent_warning_description">Por favor, escanee la tarjeta/anillo</string>
|
||||
<string name="biometric_lockout_warning_description">Por favor, inténtelo de nuevo en 30 segundos o escanee la tarjeta/anillo</string>
|
||||
<string name="biometric_lockout_warning_title">Demasiados intentos</string>
|
||||
<string name="biometric_unavailable_warning">Ha desactivado la autenticación biométrica en su teléfono y no podrá guardar billeteras en la aplicación. Para guardar billeteras, active la función de autenticación biométrica en los ajustes de su teléfono.</string>
|
||||
<string name="button_start_backup_process">Iniciar proceso de backup</string>
|
||||
<string name="buy_token_description">Utilice una tarjeta bancaria u otros métodos de pago</string>
|
||||
<plurals name="card_label_card_count">
|
||||
<item quantity="one">%d tarjeta</item>
|
||||
<item quantity="other">%d tarjetas </item>
|
||||
<item quantity="other">%d tarjetas</item>
|
||||
</plurals>
|
||||
<string name="card_settings_access_code_recovery_disabled_description">Desactive esta opción si no quiere que esta tarjeta se use para reiniciar códigos de acceso en otras tarjetas de esta billetera. Tenga en cuenta que esto también evitará que reinicie el código de acceso en esta tarjeta.</string>
|
||||
<string name="card_settings_access_code_recovery_enabled_description">Permite usar esta tarjeta para reiniciar el código de acceso en otras tarjetas de esta billetera</string>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<string name="card_settings_action_sheet_reset">Reiniciar</string>
|
||||
<string name="card_settings_action_sheet_title">¿Está seguro de que quiere hacer esto?</string>
|
||||
<string name="card_settings_change_access_code">Cambiar código de acceso</string>
|
||||
<string name="card_settings_change_access_code_footer">El código de acceso se cambiará solo en esta tarjeta</string>
|
||||
<string name="card_settings_change_access_code_footer">El código de acceso se cambiará solo en esta tarjeta o este anillo</string>
|
||||
<string name="card_settings_completed_reset_alert_message">Todas las tarjetas de la billetera seleccionada se han restablecido a la configuración de fábrica. Ahora puedes crear una nueva billetera.</string>
|
||||
<string name="card_settings_completed_reset_alert_title">Reinicio completado</string>
|
||||
<string name="card_settings_continue_reset_alert_message">¿Quiere restablecer la siguiente tarjeta en esta billetera?</string>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
<string name="card_settings_interrupted_reset_alert_title">No ha reseteado todas sus tarjetas</string>
|
||||
<string name="card_settings_reset_card_to_factory">Restablecer a ajustes de fábrica</string>
|
||||
<string name="card_settings_security_mode">Modo de seguridad</string>
|
||||
<string name="card_settings_title">Ajustes de la tarjeta</string>
|
||||
<string name="card_settings_title">Ajustes del dispositivo</string>
|
||||
<string name="cardano_coin_will_be_send_with_token_description">Además de la tarifa de red, la red Cardano cobra %1$s ADA al realizar transacciones con el %2$s token</string>
|
||||
<string name="cardano_coin_will_be_send_with_token_title">Requisitos de transacción de Cardano</string>
|
||||
<string name="cardano_insufficient_balance_to_send_token_description">Para realizar una %1$s transacción, deba depositar algo de ADA para cubrir la tarifa de red y el valor mínimo de ADA (se recomiendan 5 ADA)</string>
|
||||
|
|
@ -129,6 +129,7 @@
|
|||
<string name="common_now">Ahora</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_origin_card">Tarjeta principal</string>
|
||||
<string name="common_origin_ring">Anillo primario</string>
|
||||
<string name="common_passphrase">Frase de contraseña</string>
|
||||
<string name="common_paste">Pegar</string>
|
||||
<string name="common_privacy_policy">Política de privacidad</string>
|
||||
|
|
@ -188,7 +189,7 @@
|
|||
<string name="custom_token_invalid_derivation_path">La ruta de derivación que ha ingresado no es válida</string>
|
||||
<string name="custom_token_name_input_placeholder">Por ejemplo USD coin</string>
|
||||
<string name="custom_token_name_input_title">Nombre</string>
|
||||
<string name="custom_token_network_input_not_selected">No elegido</string>
|
||||
<string name="custom_token_network_input_not_selected">No elegida</string>
|
||||
<string name="custom_token_network_input_title">Red</string>
|
||||
<string name="custom_token_network_selector_title">Red de tokens</string>
|
||||
<string name="custom_token_subtitle">Puede agregar manualmente un token que no sea compatible de forma nativa con Tangem</string>
|
||||
|
|
@ -210,7 +211,7 @@
|
|||
<string name="details_referral_title">Programa de referidos</string>
|
||||
<string name="details_row_description_flip_to_hide">Gire la pantalla de su dispositivo hacia abajo para ocultar y mostrar rápidamente los saldos</string>
|
||||
<string name="details_row_subtitle_signed_hashes_format">%s hashes</string>
|
||||
<string name="details_row_title_cid">ID de la tarjeta</string>
|
||||
<string name="details_row_title_cid">ID del dispositivo</string>
|
||||
<string name="details_row_title_contact_to_support">Contactar con el equipo de soporte</string>
|
||||
<string name="details_row_title_create_backup">Vincular más tarjetas</string>
|
||||
<string name="details_row_title_currency">Moneda de la aplicación</string>
|
||||
|
|
@ -301,11 +302,12 @@
|
|||
<string name="initial_message_change_access_code_body">Toque para cambiar la contraseña</string>
|
||||
<string name="initial_message_change_passcode_body">Toque para cambiar la contraseña</string>
|
||||
<string name="initial_message_create_wallet_body">Para crear la billetera, toque la tarjeta como se muestra arriba y no la retire hasta el final de la operación</string>
|
||||
<string name="initial_message_create_wallet_body_ring">Para crear la billetera, ponga el anillo como se muestra arriba y manténgala hasta que termine la operación.</string>
|
||||
<string name="initial_message_reset_backup_card_header">Toque la tarjeta no. %s de la billetera</string>
|
||||
<string name="initial_message_scan_header">Coloque para escanear</string>
|
||||
<string name="initial_message_sign_header">Toque para firmar</string>
|
||||
<string name="initial_message_tap_header">Coloque la tarjeta</string>
|
||||
<string name="key_invalidated_warning_description">Ha actualizado la biometría, escanee su tarjeta para entrar</string>
|
||||
<string name="key_invalidated_warning_description">Ha actualizado la biometría, escanee su tarjeta o anillo para entrar</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_description">Su saldo debe ser mayor que el valor de la tarifa para hacer una transferencia</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_title">Saldo insuficiente</string>
|
||||
<string name="koinos_insufficient_mana_to_send_koin_description">No tiene suficiente Mana para esta transacción. Por favor, espere hasta que el Mana se recargue. Su saldo de Mana es %1$s/%2$s</string>
|
||||
|
|
@ -430,11 +432,11 @@
|
|||
<string name="markets_tooltip_message">Tire hacia arriba o toque la barra de búsqueda para agregar tokens directamente desde el mercado</string>
|
||||
<string name="markets_tooltip_title">Agregar tokens</string>
|
||||
<string name="nfc_error_unavailable">NFC no está disponible en su dispositivo</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Deba configurar un único código de acceso para proteger todas sus tarjetas</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Deba configurar un único código de acceso para proteger todss sus dispositivos.</string>
|
||||
<string name="onboarding_access_code_feature_1_title">Proteger</string>
|
||||
<string name="onboarding_access_code_feature_2_description">Puede configurar un código de acceso individual en cada tarjeta más tarde</string>
|
||||
<string name="onboarding_access_code_feature_2_title">Personalizar</string>
|
||||
<string name="onboarding_access_code_feature_3_description">El código de acceso se puede recuperar con una tarjeta vinculada. No guarde todas las tarjetas en un mismo lugar.</string>
|
||||
<string name="onboarding_access_code_feature_3_description">El código de acceso se puede recuperar con una tarjeta o un anillo vinculada(o). No guarde todas las tarjetas en un mismo lugar.</string>
|
||||
<string name="onboarding_access_code_feature_3_title">Restaurar</string>
|
||||
<string name="onboarding_access_code_hint">Elige cualquier palabra, frase o número que quieras como su código de acceso</string>
|
||||
<string name="onboarding_access_code_intro_title">Crear un código de acceso</string>
|
||||
|
|
@ -448,10 +450,12 @@
|
|||
<string name="onboarding_alert_message_not_max_backup_cards_added">Ha agregado una tarjeta de backup. Cuando el proceso de backup finalice, no podrá añadir más tarjetas de backup. Si tiene otra tarjeta, agréguela al backup. ¿Quiere continuar el proceso de backup?</string>
|
||||
<string name="onboarding_backup_exit_warning">El proceso de backup está parcialmente completo. No puede salir ahora.</string>
|
||||
<string name="onboarding_bottom_sheet_passphrase_description">La frase de contraseña es una característica de seguridad avanzada utilizada por las billeteras criptográficas. Agrega una palabra o frase adicional de su elección a su frase de recuperación ya existente para desbloquear un conjunto completamente nuevo de direcciones.</string>
|
||||
<string name="onboarding_button_add_backup_card">Agregar una tarjeta de backup</string>
|
||||
<string name="onboarding_button_add_backup_card">Agregar una tarjeta o un anillo de backup</string>
|
||||
<string name="onboarding_button_backup_card">Escanee la tarjeta</string>
|
||||
<string name="onboarding_button_backup_card_format">Escanee la tarjeta no. %d</string>
|
||||
<string name="onboarding_button_backup_now">Hacer backup ahora</string>
|
||||
<string name="onboarding_button_backup_origin">Escanee la tarjeta principal</string>
|
||||
<string name="onboarding_button_backup_ring">Escanee el anillo</string>
|
||||
<string name="onboarding_button_continue_wallet">Continuar a mi billetera</string>
|
||||
<string name="onboarding_button_finalize_backup">Finalizar el backup</string>
|
||||
<string name="onboarding_button_receive_crypto">Recibir cripto</string>
|
||||
|
|
@ -462,7 +466,7 @@
|
|||
<string name="onboarding_create_wallet_button_create_wallet">Crear una billetera</string>
|
||||
<string name="onboarding_create_wallet_header">Crear una billetera</string>
|
||||
<string name="onboarding_create_wallet_options_button_options">Otras opciones</string>
|
||||
<string name="onboarding_create_wallet_options_message">Sus claves se generarán de forma segura dentro de la tarjeta. No hay seed phrase, lo que significa que nadie puede exportarla ni robarla.</string>
|
||||
<string name="onboarding_create_wallet_options_message">Sus claves se generarán de forma segura dentro del chip. No hay seed phrase, lo que significa que nadie puede exportarla ni robarla.</string>
|
||||
<string name="onboarding_create_wallet_options_title">Generar claves de forma privada</string>
|
||||
<string name="onboarding_done_body">Su tarjeta está activada y lista para usar</string>
|
||||
<string name="onboarding_done_header">¡Éxito!</string>
|
||||
|
|
@ -494,13 +498,16 @@
|
|||
<string name="onboarding_subtitle_no_backup_cards">Para iniciar el proceso de backup, agregue hasta dos tarjetas de backup.</string>
|
||||
<string name="onboarding_subtitle_one_backup_card">Puede agregar una tarjeta más o finalizar el proceso de backup</string>
|
||||
<string name="onboarding_subtitle_scan_backup_card_format">Prepare su tarjeta de backup con el no.%s</string>
|
||||
<string name="onboarding_subtitle_scan_primary">Escanee la tarjeta principal para iniciar el proceso de backup.</string>
|
||||
<string name="onboarding_subtitle_scan_primary">Escanee la tarjeta principal o el anillo para iniciar el proceso de backup.</string>
|
||||
<string name="onboarding_subtitle_scan_primary_card_format">Prepare la tarjeta principal con el número %s</string>
|
||||
<string name="onboarding_subtitle_scan_ring">Prepare el anillo y presione el botón de escaneo a continuación</string>
|
||||
<string name="onboarding_subtitle_success_tangem_wallet_onboarding">Su tarjeta billetera está configurada y lista para usar.</string>
|
||||
<string name="onboarding_subtitle_two_backup_cards">Número máximo de tarjetas añadido. Finalice el proceso de backup.</string>
|
||||
<string name="onboarding_title">Activando tarjeta</string>
|
||||
<string name="onboarding_title_backup_card">Tarjeta de backup</string>
|
||||
<string name="onboarding_title_backup_card_format">Tarjeta de backup no.%d</string>
|
||||
<string name="onboarding_title_no_backup_cards">Ningunas tarjetas de backup</string>
|
||||
<string name="onboarding_title_backup_ring">Anillo de backup</string>
|
||||
<string name="onboarding_title_no_backup_cards">Ningunos dispositivos de backup</string>
|
||||
<string name="onboarding_title_notifications">Notificaciones</string>
|
||||
<string name="onboarding_title_one_backup_card">Una tarjeta de backup agregada</string>
|
||||
<string name="onboarding_title_scan_origin_card">Prepare su tarjeta</string>
|
||||
|
|
@ -656,7 +663,7 @@
|
|||
<string name="send_transaction_success">La transacción se firmó con éxito y se envió al nodo blockchain. El saldo de la billetera se actualizará después de un tiempo.</string>
|
||||
<string name="send_tron_account_activation_error">%1$s es un activo en la red Tron. Para calcular la tarifa y realizar una transacción, deba depositar algo de Tron (TRX) en su cuenta.</string>
|
||||
<string name="sent_transaction_sent_title">Transacción enviada</string>
|
||||
<string name="settings_card_settings_footer">Escanee la tarjeta que quiere configurar</string>
|
||||
<string name="settings_card_settings_footer">Escanee la tarjeta/anillo que quiere configurar</string>
|
||||
<string name="settings_forget_wallet">Olvidar la billetera</string>
|
||||
<string name="settings_forget_wallet_footer">Esto eliminará la wallet de la aplicación. La wallet en sí puede\nañadirse de nuevo.</string>
|
||||
<string name="settings_wallet_name_title">Nombre</string>
|
||||
|
|
@ -752,7 +759,7 @@
|
|||
<string name="staking_your_stakes">Sus stakes</string>
|
||||
<string name="story_awe_description">Almacene sus activos crypto de forma segura manteniendo las claves privadas contenidas en su tarjeta</string>
|
||||
<string name="story_awe_title">Billetera de hardware revolucionaria</string>
|
||||
<string name="story_backup_description">Hasta 3 tarjetas físicas por billetera</string>
|
||||
<string name="story_backup_description">Hasta 3 tarjetas físicas o anillos por billetera</string>
|
||||
<string name="story_backup_title">Backup ultra seguro</string>
|
||||
<string name="story_currencies_description">Una billetera de hardware para su Bitcoin, Ethereum y muchas más monedas simultáneamente – todo en una sola tarjeta</string>
|
||||
<string name="story_currencies_title">Miles de monedas</string>
|
||||
|
|
@ -823,13 +830,13 @@
|
|||
<string name="twins_recreate_toolbar">Tangem Twin</string>
|
||||
<string name="twins_recreate_warning">Esta acción es irreversible. No tendrá acceso la billetera antigua.</string>
|
||||
<string name="twins_scan_twin_with_number">Toque la tarjeta gemela con el número %s y no la retira hasta el final de la operación</string>
|
||||
<string name="unlock_wallet_description_full">Use %s o escanee una tarjeta para tener acceso a su billetera</string>
|
||||
<string name="unlock_wallet_description_full">Use %s o escanee una tarjeta/anillo para tener acceso a su billetera</string>
|
||||
<string name="user_push_notification_agreement_argument_one">Manténgase actualizado con las últimas funciones y noticias</string>
|
||||
<string name="user_push_notification_agreement_argument_two">Sea el primero en enterarte de nuevas promociones</string>
|
||||
<string name="user_push_notification_agreement_header">¿Quiere utilizar\nnotificaciones push?</string>
|
||||
<string name="user_wallet_list_add_button">Agregar una nueva billetera</string>
|
||||
<string name="user_wallet_list_delete_prompt">¿Está seguro(a) de que quieres eliminar esta billetera?</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">Ha ocurrido un error, por favor escanee su tarjeta para iniciar sesión</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">Ha ocurrido un error, por favor escanee su tarjeta o anillo para iniciar sesión</string>
|
||||
<string name="user_wallet_list_error_wallet_already_saved">Esta billetera ya se ha guardado, puede agregar otro</string>
|
||||
<string name="user_wallet_list_rename_popup_error_already_exists">La billetera con el nombre %s ya existe</string>
|
||||
<string name="user_wallet_list_rename_popup_placeholder">Nombre de la billetera</string>
|
||||
|
|
@ -837,7 +844,7 @@
|
|||
<string name="user_wallet_list_unlock_all">Desbloquear todo</string>
|
||||
<string name="user_wallet_list_unlock_all_with">Desbloquear todo con %s</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">La blockchain está Inaccesible. Inténtelo más tarde</string>
|
||||
<string name="wallet_balance_missing_derivation">Escanee la tarjeta</string>
|
||||
<string name="wallet_balance_missing_derivation">Escanee la tarjeta o el anillo</string>
|
||||
<string name="wallet_connect_alert_sign_message">Solicitud para firmar un mensaje.\n\n%s</string>
|
||||
<string name="wallet_connect_bnb_sign_message">Dapp %1$s, solicitando\nfirmar transacción BNB.\n\n%2$s</string>
|
||||
<string name="wallet_connect_bnb_trade_order_message">Orden de intercambio por %1$s\nPrecio: %2$s\nCantidad a recibir: %3$s\nCantidad a pagar: %4$s</string>
|
||||
|
|
@ -851,7 +858,7 @@
|
|||
<string name="wallet_connect_error_unsupported_blockchains">La solicitud de sesión contiene blockchains no compatibles para la conexión WalletConnect. Blockchains no compatibles:\n</string>
|
||||
<string name="wallet_connect_error_unsupported_dapp">La conexión con esta dApp no se puede establecer debido a su implementación técnica.</string>
|
||||
<string name="wallet_connect_error_with_framework_message">Hemos encontrado un error desconocido. Mensaje de error: %s. Si el problema persiste, no duda en contactar con nuestro soporte</string>
|
||||
<string name="wallet_connect_error_wrong_card_selected">Tarjeta incorrecta seleccionada en Tangem App</string>
|
||||
<string name="wallet_connect_error_wrong_card_selected">Tarjeta/anillo incorrecta (o) seleccionada en Tangem App</string>
|
||||
<string name="wallet_connect_failed_to_build_tx">Error al crear la transacción a partir de los datos de la dApp. Código: %s</string>
|
||||
<string name="wallet_connect_generic_error_with_code">Hemos encontrado un error desconocido. Mensaje de error: %d. Si el problema persiste, contacte con nuestro soporte</string>
|
||||
<string name="wallet_connect_no_sessions_message">No hay sesiones abiertas de WalletConnect</string>
|
||||
|
|
@ -876,7 +883,7 @@
|
|||
<string name="wallet_notification_no_internet">Sin conexión a internet</string>
|
||||
<string name="wallet_settings_title">Ajusta de la wallet</string>
|
||||
<string name="wallet_title">Tangem</string>
|
||||
<string name="warning_access_denied_message">Use %s o escanee una tarjeta para desbloquear el acceso a su billetera</string>
|
||||
<string name="warning_access_denied_message">Use %s o escanee una tarjeta/anillo para desbloquear el acceso a su billetera</string>
|
||||
<string name="warning_approval_in_progress_message">El proceso de obtención de permisos está actualmente en marcha y se completará pronto.</string>
|
||||
<string name="warning_approval_in_progress_title">Aprobación en curso</string>
|
||||
<string name="warning_backup_errors_message">Parece que la activación de la tarjeta no ha ido correctamente. Esto puede deberse a un problema con el módulo NFC de su dispositivo o a una mala conexión de la tarjeta de su dispositivo. Comuníquese con nuestro equipo de soporte para obtener ayuda.</string>
|
||||
|
|
@ -925,8 +932,8 @@
|
|||
<string name="warning_matic_migration_message">Actualmente, MATIC está migrando a POL. Sin embargo, no se ha fijado ninguna fecha límite y MATIC aún no está obsoleto. Puede seguir usando el token MATIC de forma segura o utilizar intercambios para cambiarlo por POL.</string>
|
||||
<string name="warning_matic_migration_title">Migración de MATIC a POL</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="one">Use su tarjeta para obtener una dirección para la red</item>
|
||||
<item quantity="other">Use su tarjeta para obtener direcciónes para la red</item>
|
||||
<item quantity="one">Use su tarjeta o anillo para obtener una dirección para la red</item>
|
||||
<item quantity="other">Use su tarjeta o anillo para obtener direcciónes para la red</item>
|
||||
</plurals>
|
||||
<string name="warning_missing_derivation_title">Faltan algunas direcciones</string>
|
||||
<string name="warning_network_unreachable_message">La red no está disponible actualmente. Por favor, inténtalo de nuevo más tarde.</string>
|
||||
|
|
@ -953,7 +960,7 @@
|
|||
<string name="welcome_interrupted_backup_alert_message">Tiene un backup interrumpido. ¿Quiere reanudarlo?</string>
|
||||
<string name="welcome_interrupted_backup_alert_resume">Sí, reanudar</string>
|
||||
<string name="welcome_interrupted_backup_discard_discard">Descartar</string>
|
||||
<string name="welcome_interrupted_backup_discard_message">Si descarta el backup ahora, tendrá que restablecer las tarjetas a los ajustes de fábrica para empezar de nuevo</string>
|
||||
<string name="welcome_interrupted_backup_discard_message">Si descarta el backup ahora, tendrá que restablecer los dispositivos a los ajustes de fábrica para empezar de nuevo</string>
|
||||
<string name="welcome_interrupted_backup_discard_resume">Reanudar backup</string>
|
||||
<string name="welcome_interrupted_backup_discard_title">Esta es una acción irreversible</string>
|
||||
<string name="welcome_unlock">Iniciar sesión con %s</string>
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@
|
|||
<string name="balance_hidden_do_not_show_button">Ne plus afficher</string>
|
||||
<string name="balance_hidden_got_it_button">Compris</string>
|
||||
<string name="balance_hidden_title">Les soldes sont masqués</string>
|
||||
<string name="biometric_lockout_permanent_warning_description">Veuillez scanner la carte</string>
|
||||
<string name="biometric_lockout_warning_description">Veuillez réessayer dans 30 secondes ou scannez la carte</string>
|
||||
<string name="biometric_lockout_permanent_warning_description">Veuillez scanner la carte/bague</string>
|
||||
<string name="biometric_lockout_warning_description">Veuillez réessayer dans 30 secondes ou scannez la carte/bague</string>
|
||||
<string name="biometric_lockout_warning_title">Trop de tentatives</string>
|
||||
<string name="biometric_unavailable_warning">Vous avez désactivé l\'authentification biométrique sur votre téléphone et ne pourrez pas enregistrer de portefeuilles dans l\'application. Pour enregistrer des portefeuilles, veuillez activer la fonction d\'authentification biométrique dans les paramètres de votre téléphone.</string>
|
||||
<string name="button_start_backup_process">Démarrer le processus de sauvegarde</string>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<string name="card_settings_action_sheet_reset">Réinitialiser</string>
|
||||
<string name="card_settings_action_sheet_title">Êtes-vous sûr de vouloir faire cela ?</string>
|
||||
<string name="card_settings_change_access_code">Modifier le code d\'accès</string>
|
||||
<string name="card_settings_change_access_code_footer">Le code d\'accès ne sera modifié que sur cette carte</string>
|
||||
<string name="card_settings_change_access_code_footer">Le code d\'accès ne sera modifié que sur cette carte ou cette bague</string>
|
||||
<string name="card_settings_completed_reset_alert_message">Toutes les cartes du portefeuille sélectionné ont été réinitialisées aux paramètres d\'usine. Vous pouvez maintenant créer un nouveau portefeuille.</string>
|
||||
<string name="card_settings_completed_reset_alert_title">Réinitialisation terminée</string>
|
||||
<string name="card_settings_continue_reset_alert_message">Voulez-vous réinitialiser la prochaine carte de ce portefeuille ?</string>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
<string name="card_settings_interrupted_reset_alert_title">Vous n\'avez pas réinitialisé toutes vos cartes</string>
|
||||
<string name="card_settings_reset_card_to_factory">Réinitialiser aux paramètres d\'usine</string>
|
||||
<string name="card_settings_security_mode">Mode de sécurité</string>
|
||||
<string name="card_settings_title">Paramètres de la carte</string>
|
||||
<string name="card_settings_title">Paramètres de l\'appareil</string>
|
||||
<string name="cardano_coin_will_be_send_with_token_description">En plus des frais de réseau, le réseau Cardano facture %1$s de l\'ADA lors des transactions avec le jeton %2$s</string>
|
||||
<string name="cardano_coin_will_be_send_with_token_title">Exigences pour les transactions Cardano</string>
|
||||
<string name="cardano_insufficient_balance_to_send_token_description">Pour effectuer une transaction %1$s, vous devez déposer de l\'ADA pour couvrir les frais de réseau et la valeur minimale en ADA (5 ADA recommandés)</string>
|
||||
|
|
@ -129,6 +129,7 @@
|
|||
<string name="common_now">Maintenant</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_origin_card">Carte principale</string>
|
||||
<string name="common_origin_ring">Bague principale</string>
|
||||
<string name="common_passphrase">Passphrase</string>
|
||||
<string name="common_paste">Coller</string>
|
||||
<string name="common_privacy_policy">Politique de confidentialité</string>
|
||||
|
|
@ -210,7 +211,7 @@
|
|||
<string name="details_referral_title">Programme de parrainage</string>
|
||||
<string name="details_row_description_flip_to_hide">Retournez l\'écran de votre appareil vers le bas pour masquer et afficher rapidement les soldes</string>
|
||||
<string name="details_row_subtitle_signed_hashes_format">%s hashes</string>
|
||||
<string name="details_row_title_cid">ID de la carte</string>
|
||||
<string name="details_row_title_cid">ID de l\'appareil</string>
|
||||
<string name="details_row_title_contact_to_support">Contactez l\'équipe de support</string>
|
||||
<string name="details_row_title_create_backup">Lier plus de cartes</string>
|
||||
<string name="details_row_title_currency">Monnaie de l\'application</string>
|
||||
|
|
@ -301,11 +302,12 @@
|
|||
<string name="initial_message_change_access_code_body">Touchez, pour modifier le code d\'accès</string>
|
||||
<string name="initial_message_change_passcode_body">Touchez, pour modifier le mot de passe</string>
|
||||
<string name="initial_message_create_wallet_body">Pour créer le portefeuille, appuyez sur la carte comme indiqué ci-dessus et ne la retirez pas jusqu\'à la fin de l\'opération</string>
|
||||
<string name="initial_message_create_wallet_body_ring">Pour créer le portefeuille, appuyez sur l\'anneau comme indiqué ci-dessus et ne le retirez pas avant la fin de l\'opération</string>
|
||||
<string name="initial_message_reset_backup_card_header">Appuyez sur la carte n°%s du portefeuille</string>
|
||||
<string name="initial_message_scan_header">Posez pour scanner</string>
|
||||
<string name="initial_message_sign_header">Tapez pour signer</string>
|
||||
<string name="initial_message_tap_header">Posez la carte</string>
|
||||
<string name="key_invalidated_warning_description">Vous avez mis à jour vos données biométriques, scannez votre carte pour entrer</string>
|
||||
<string name="key_invalidated_warning_description">Vous avez mis à jour vos données biométriques, scannez votre carte ou bague pour entrer</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_description">Votre solde doit être supérieur à la valeur des frais pour effectuer un transfert</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_title">Solde insuffisant</string>
|
||||
<string name="koinos_insufficient_mana_to_send_koin_description">Vous n\'avez pas assez de Mana pour cette transaction. Veuillez attendre que le Mana soit reconstitué. Votre solde de Mana est de %1$s/%2$s</string>
|
||||
|
|
@ -430,11 +432,11 @@
|
|||
<string name="markets_tooltip_message">Tirez vers le haut ou appuyez sur la barre de recherche pour ajouter des jetons directement depuis le marché</string>
|
||||
<string name="markets_tooltip_title">Ajouter des jetons</string>
|
||||
<string name="nfc_error_unavailable">NFC n\'est pas disponible sur votre appareil</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Vous devez définir un seul code d\'accès pour protéger toutes vos cartes</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Vous devez définir un seul code d\'accès pour protéger tous vos appareils.</string>
|
||||
<string name="onboarding_access_code_feature_1_title">Protéger</string>
|
||||
<string name="onboarding_access_code_feature_2_description">Vous pourrez définir un code d\'accès individuel sur chaque carte plus tard</string>
|
||||
<string name="onboarding_access_code_feature_2_title">Personnaliser</string>
|
||||
<string name="onboarding_access_code_feature_3_description">Le code d\'accès peut être restauré avec une carte liée. Ne gardez pas toutes les cartes au même endroit.</string>
|
||||
<string name="onboarding_access_code_feature_3_description">Le code d\'accès peut être restauré avec une carte ou bague liée. Ne gardez pas toutes les cartes au même endroit.</string>
|
||||
<string name="onboarding_access_code_feature_3_title">Restaurer</string>
|
||||
<string name="onboarding_access_code_hint">Choisissez n\'importe quel mot, phrase ou nombre que vous souhaitez comme code d\'accès</string>
|
||||
<string name="onboarding_access_code_intro_title">Créer un code d\'accès</string>
|
||||
|
|
@ -448,10 +450,12 @@
|
|||
<string name="onboarding_alert_message_not_max_backup_cards_added">Vous avez ajouté une carte de sauvegarde. Une fois le processus de sauvegarde terminé, vous ne pourrez plus ajouter de cartes de sauvegarde. Si vous avez une autre carte, ajoutez-la à la sauvegarde. Souhaitez-vous poursuivre le processus de sauvegarde ?</string>
|
||||
<string name="onboarding_backup_exit_warning">Le processus de sauvegarde est partiellement terminé. Vous ne pouvez pas le quitter maintenant.</string>
|
||||
<string name="onboarding_bottom_sheet_passphrase_description">La phrase secrète est une fonctionnalité de sécurité avancée utilisée par les portefeuilles cryptographiques. Il ajoute un mot ou une phrase supplémentaire de votre choix à votre phrase de récupération déjà existante pour débloquer un tout nouvel ensemble d\'adresses.</string>
|
||||
<string name="onboarding_button_add_backup_card">Ajouter une carte de sauvegarde</string>
|
||||
<string name="onboarding_button_add_backup_card">Ajouter une carte ou bague de sauvegarde</string>
|
||||
<string name="onboarding_button_backup_card">Scannez la carte</string>
|
||||
<string name="onboarding_button_backup_card_format">Scannez la carte n°%d</string>
|
||||
<string name="onboarding_button_backup_now">Sauvegarder maintenant</string>
|
||||
<string name="onboarding_button_backup_origin">Scannez la carte principale</string>
|
||||
<string name="onboarding_button_backup_ring">Scannez la bague</string>
|
||||
<string name="onboarding_button_continue_wallet">Continuer vers mon portefeuille</string>
|
||||
<string name="onboarding_button_finalize_backup">Finaliser la sauvegarde</string>
|
||||
<string name="onboarding_button_receive_crypto">Recevoir des crypto-monnaies</string>
|
||||
|
|
@ -462,7 +466,7 @@
|
|||
<string name="onboarding_create_wallet_button_create_wallet">Créer un portefeuille</string>
|
||||
<string name="onboarding_create_wallet_header">Créer un portefeuille</string>
|
||||
<string name="onboarding_create_wallet_options_button_options">Autres options</string>
|
||||
<string name="onboarding_create_wallet_options_message">Vos clés seront générées de manière sécurisée à l\'intérieur de la carte. Il n\'y a pas de seed phrase, ce qui signifie que personne ne peut l\'exporter ou la voler.</string>
|
||||
<string name="onboarding_create_wallet_options_message">Vos clés seront générées de manière sécurisée à l\'intérieur de la puce. Il n\'y a pas de seed phrase, ce qui signifie que personne ne peut l\'exporter ou la voler.</string>
|
||||
<string name="onboarding_create_wallet_options_title">Générer des clés de manière privée</string>
|
||||
<string name="onboarding_done_body">Votre carte est activée et prête à être utilisée</string>
|
||||
<string name="onboarding_done_header">Succès !</string>
|
||||
|
|
@ -494,13 +498,16 @@
|
|||
<string name="onboarding_subtitle_no_backup_cards">Pour démarrer le processus de sauvegarde, ajoutez jusqu\'à deux cartes de sauvegarde.</string>
|
||||
<string name="onboarding_subtitle_one_backup_card">Vous pouvez ajouter une carte supplémentaire ou finaliser le processus de sauvegarde</string>
|
||||
<string name="onboarding_subtitle_scan_backup_card_format">Préparez la carte de sauvegarde avec le numéro %s</string>
|
||||
<string name="onboarding_subtitle_scan_primary">Scannez la carte principale pour démarrer le processus de sauvegarde.</string>
|
||||
<string name="onboarding_subtitle_scan_primary">Scannez la carte principale ou bague pour démarrer le processus de sauvegarde.</string>
|
||||
<string name="onboarding_subtitle_scan_primary_card_format">Préparez la carte principale avec le numéro %s</string>
|
||||
<string name="onboarding_subtitle_scan_ring">Préparez la bague et appuyez sur le bouton de numérisation ci-dessous</string>
|
||||
<string name="onboarding_subtitle_success_tangem_wallet_onboarding">Votre carte de portefeuille est configurée et prête à l\'emploi.</string>
|
||||
<string name="onboarding_subtitle_two_backup_cards">Nombre maximum de cartes ajoutées. Finalisez le processus de sauvegarde.</string>
|
||||
<string name="onboarding_title">Activation de la carte</string>
|
||||
<string name="onboarding_title_backup_card">Carte de sauvegarde</string>
|
||||
<string name="onboarding_title_backup_card_format">Carte de sauvegarde n°%d</string>
|
||||
<string name="onboarding_title_no_backup_cards">Aucune carte de sauvegarde</string>
|
||||
<string name="onboarding_title_backup_ring">Bague de sauvegarde</string>
|
||||
<string name="onboarding_title_no_backup_cards">Aucun appareil de sauvegarde</string>
|
||||
<string name="onboarding_title_notifications">Notifications</string>
|
||||
<string name="onboarding_title_one_backup_card">Une carte de sauvegarde ajoutée</string>
|
||||
<string name="onboarding_title_scan_origin_card">Préparez votre carte</string>
|
||||
|
|
@ -656,7 +663,7 @@
|
|||
<string name="send_transaction_success">La transaction a été signée avec succès et envoyée au nœud de blockchain. Le solde du portefeuille sera mis à jour après un certain temps</string>
|
||||
<string name="send_tron_account_activation_error">%1$s est un actif du réseau Tron. Pour calculer les frais et effectuer une transaction, déposez du Tron (TRX) sur votre compte.</string>
|
||||
<string name="sent_transaction_sent_title">Transaction envoyée</string>
|
||||
<string name="settings_card_settings_footer">Scannez la carte que vous souhaitez configurer.</string>
|
||||
<string name="settings_card_settings_footer">Scannez la carte/ bague que vous souhaitez configurer.</string>
|
||||
<string name="settings_forget_wallet">Oublier le portefeuille</string>
|
||||
<string name="settings_forget_wallet_footer">Cela supprimera le portefeuille de l\'application. Le portefeuille lui-même peut être ajouté à nouveau.</string>
|
||||
<string name="settings_wallet_name_title">Nom</string>
|
||||
|
|
@ -752,7 +759,7 @@
|
|||
<string name="staking_your_stakes">Vos stakes</string>
|
||||
<string name="story_awe_description">Stockez vos actifs crypto en toute sécurité tout en conservant les clés privées contenues dans votre carte</string>
|
||||
<string name="story_awe_title">Portefeuille matériel révolutionnaire</string>
|
||||
<string name="story_backup_description">Jusqu\'à 3 cartes physiques pour un portefeuille</string>
|
||||
<string name="story_backup_description">Jusqu\'à 3 cartes physiques ou bagues pour un portefeuille</string>
|
||||
<string name="story_backup_title">Sauvegarde ultra sécurisée</string>
|
||||
<string name="story_currencies_description">Un portefeuille matériel pour vos Bitcoin, Ethereum et de nombreuses autres devises simultanément, le tout dans une seule carte</string>
|
||||
<string name="story_currencies_title">Des milliers de devises</string>
|
||||
|
|
@ -823,13 +830,13 @@
|
|||
<string name="twins_recreate_toolbar">Tangem Twin</string>
|
||||
<string name="twins_recreate_warning">Cette action est irréversible. Vous n\'aurez plus accès à l\'ancien portefeuille.</string>
|
||||
<string name="twins_scan_twin_with_number">Appuyez sur la carte jumelle avec le numéro %s et ne la retirez pas jusqu\'à la fin de l\'opération</string>
|
||||
<string name="unlock_wallet_description_full">Utilisez %s ou scannez une carte pour avoir accès à votre portefeuille</string>
|
||||
<string name="unlock_wallet_description_full">Utilisez %s ou scannez une carte/bague pour avoir accès à votre portefeuille</string>
|
||||
<string name="user_push_notification_agreement_argument_one">Restez à jour avec les dernières fonctionnalités et actualités</string>
|
||||
<string name="user_push_notification_agreement_argument_two">Soyez le premier informé des nouvelles promotions</string>
|
||||
<string name="user_push_notification_agreement_header">Souhaitez-vous utiliser les\nnotifications push?</string>
|
||||
<string name="user_wallet_list_add_button">Ajouter un nouveau portefeuille</string>
|
||||
<string name="user_wallet_list_delete_prompt">Êtes-vous sûr de vouloir supprimer ce portefeuille ?</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">Une erreur s\'est produite, veuillez scanner votre carte pour vous connecter</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">Une erreur s\'est produite, veuillez scanner votre carte ou bague pour vous connecter</string>
|
||||
<string name="user_wallet_list_error_wallet_already_saved">Ce portefeuille a déjà été enregistré, vous pouvez en ajouter un autre</string>
|
||||
<string name="user_wallet_list_rename_popup_error_already_exists">Le portefeuille portant le nom %s existe déjà</string>
|
||||
<string name="user_wallet_list_rename_popup_placeholder">Nom du portefeuille</string>
|
||||
|
|
@ -837,7 +844,7 @@
|
|||
<string name="user_wallet_list_unlock_all">Tout déverrouiller</string>
|
||||
<string name="user_wallet_list_unlock_all_with">Tout déverrouiller avec %s</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">La blockchain n\'est pas accessible. Réessayez plus tard</string>
|
||||
<string name="wallet_balance_missing_derivation">Scanner la carte</string>
|
||||
<string name="wallet_balance_missing_derivation">Scanner la carte ou la bague</string>
|
||||
<string name="wallet_connect_alert_sign_message">Demande de signature d\'un message.\n\n%s</string>
|
||||
<string name="wallet_connect_bnb_sign_message">Dapp %1$s, demandant de\nsigner la transaction BNB.\n\n%2$s</string>
|
||||
<string name="wallet_connect_bnb_trade_order_message">Ordre de trade pour %1$s\nPrix : %2$s\nMontant à recevoir : %3$s\nMontant à payer : %4$s</string>
|
||||
|
|
@ -851,7 +858,7 @@
|
|||
<string name="wallet_connect_error_unsupported_blockchains">La demande de session contient des blockchains non prises en charge pour la connexion WalletConnect. Blockchains non prises en charge :\n</string>
|
||||
<string name="wallet_connect_error_unsupported_dapp">La connexion avec cette dApp ne peut pas être établie en raison de son implémentation technique.</string>
|
||||
<string name="wallet_connect_error_with_framework_message">Nous avons rencontré une erreur inconnue. Message d\'erreur : %s. Si le problème persiste, n\'hésitez pas à contacter notre support</string>
|
||||
<string name="wallet_connect_error_wrong_card_selected">Mauvaise carte sélectionnée dans le Tangem App</string>
|
||||
<string name="wallet_connect_error_wrong_card_selected">Mauvaise carte/bague sélectionnée dans le Tangem App</string>
|
||||
<string name="wallet_connect_failed_to_build_tx">Échec de la création de la transaction à partir des données de la Dapp. Code: %s</string>
|
||||
<string name="wallet_connect_generic_error_with_code">Nous avons rencontré une erreur inconnue. Code d\'erreur : %d. Si le problème persiste, n\'hésitez pas à contacter notre support</string>
|
||||
<string name="wallet_connect_no_sessions_message">Aucune session WalletConnect ouverte</string>
|
||||
|
|
@ -876,7 +883,7 @@
|
|||
<string name="wallet_notification_no_internet">Pas de connexion internet</string>
|
||||
<string name="wallet_settings_title">Paramètres du portefeuille</string>
|
||||
<string name="wallet_title">Tangem</string>
|
||||
<string name="warning_access_denied_message">Utilisez %s ou scannez une carte pour déverrouiller l\'accès à votre portefeuille</string>
|
||||
<string name="warning_access_denied_message">Utilisez %s ou scannez une carte/bague pour déverrouiller l\'accès à votre portefeuille</string>
|
||||
<string name="warning_approval_in_progress_message">Le processus d\'octroi des autorisations est actuellement en cours et sera bientôt terminé</string>
|
||||
<string name="warning_approval_in_progress_title">Approbation en cours</string>
|
||||
<string name="warning_backup_errors_message">Il semble que l\'activation de la carte ne se soit pas déroulée correctement. Cela peut être dû à un problème avec le module NFC de votre appareil ou à une mauvaise connexion de la carte sur votre appareil. Veuillez contacter notre équipe de support pour obtenir de l’aide.</string>
|
||||
|
|
@ -922,11 +929,11 @@
|
|||
<string name="warning_low_signatures_message">Il ne reste que %s signatures sur cette carte. Vous devez retirer tous vos fonds.</string>
|
||||
<string name="warning_low_signatures_title">Faible nombre de signatures</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Les jetons sur différents réseaux peuvent avoir des adresses différentes. Vérifiez bien que votre adresse correspond au réseau lorsque vous transférez des fonds.</string>
|
||||
<string name="warning_matic_migration_message">MATIC est en cours de migration vers POL. Cependant, aucune date limite n\'a été fixée et MATIC n\'est pas encore obsolète. Vous pouvez continuer à utiliser le jeton MATIC en toute sécurité ou utiliser des échanges pour l\'échanger contre POL.</string>
|
||||
<string name="warning_matic_migration_message">MATIC est en cours de migration vers POL. Cependant, aucune date limite n\'a été fixée et MATIC n\'est pas encore obsolète. Vous pouvez continuer à utiliser le jeton MATIC en toute sécurité ou l\'échanger contre POL.</string>
|
||||
<string name="warning_matic_migration_title">Migration de MATIC vers POL</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="one">Utilisez votre carte pour obtenir une adresse pour le réseau %d</item>
|
||||
<item quantity="other">Utilisez votre carte pour obtenir des adresses pour les réseaux %d</item>
|
||||
<item quantity="one">Utilisez votre carte ou bague pour obtenir une adresse pour le réseau %d</item>
|
||||
<item quantity="other">Utilisez votre carte ou bague pour obtenir des adresses pour les réseaux %d</item>
|
||||
</plurals>
|
||||
<string name="warning_missing_derivation_title">Certaines adresses sont manquantes</string>
|
||||
<string name="warning_network_unreachable_message">Le réseau est actuellement inaccessible. Veuillez réessayer plus tard.</string>
|
||||
|
|
@ -953,7 +960,7 @@
|
|||
<string name="welcome_interrupted_backup_alert_message">Vous avez une sauvegarde interrompue. Voulez-vous la reprendre ?</string>
|
||||
<string name="welcome_interrupted_backup_alert_resume">Oui, reprendre</string>
|
||||
<string name="welcome_interrupted_backup_discard_discard">Ignorer</string>
|
||||
<string name="welcome_interrupted_backup_discard_message">Si vous ignorez la sauvegarde maintenant, vous devrez réinitialiser les cartes aux paramètres d\'usine pour recommencer</string>
|
||||
<string name="welcome_interrupted_backup_discard_message">Si vous ignorez la sauvegarde maintenant, vous devrez réinitialiser les appareils aux paramètres d\'usine pour recommencer</string>
|
||||
<string name="welcome_interrupted_backup_discard_resume">Reprendre la sauvegarde</string>
|
||||
<string name="welcome_interrupted_backup_discard_title">C\'est une action irréversible</string>
|
||||
<string name="welcome_unlock">Se connecter avec %s</string>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
<string name="card_settings_action_sheet_reset">リセット</string>
|
||||
<string name="card_settings_action_sheet_title">本当に実行しますか?</string>
|
||||
<string name="card_settings_change_access_code">アクセスコードの変更</string>
|
||||
<string name="card_settings_change_access_code_footer">アクセスコードは、このカードのみで変更されます</string>
|
||||
<string name="card_settings_change_access_code_footer">アクセスコードは、このカードまたはリングによってのみ変更されます</string>
|
||||
<string name="card_settings_completed_reset_alert_message">選択したウォレットのすべてのTangemデバイスが、工場出荷時の設定にリセットされました。これで、新しいウォレットを作成できます。</string>
|
||||
<string name="card_settings_completed_reset_alert_title">リセット完了</string>
|
||||
<string name="card_settings_continue_reset_alert_message">このウォレットの次のデバイスをリセットしますか?</string>
|
||||
|
|
@ -210,7 +210,7 @@
|
|||
<string name="details_manage_security_access_code">アクセスコード</string>
|
||||
<string name="details_manage_security_access_code_description">カードをスキャンする前に、正しいアクセスコードを送信する必要があります。</string>
|
||||
<string name="details_manage_security_long_tap">長くタップ</string>
|
||||
<string name="details_manage_security_long_tap_description">このメカニズムは、カードまたはリングに対する近接攻撃から保護します。コマンドの受信と実行の間に遅延を強制します。 </string>
|
||||
<string name="details_manage_security_long_tap_description">このメカニズムは、カードまたはリングに対する近接攻撃から保護します。コマンドの受信と実行の間に遅延を強制します。</string>
|
||||
<string name="details_manage_security_passcode">パスコード</string>
|
||||
<string name="details_manage_security_passcode_description">カードの状態の変更を伴うコマンドを実行する前に、パスコードを入力する必要があります。</string>
|
||||
<string name="details_referral_title">紹介プログラム</string>
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@
|
|||
<string name="give_permission_unlimited">Безлимитно</string>
|
||||
<string name="home_button_order">Купить</string>
|
||||
<string name="home_button_scan">Сканировать</string>
|
||||
<string name="information_generated_with_ai">Информация сгенерирована ИИ</string>
|
||||
<string name="information_generated_with_ai">Эта информация была сгенерирована ИИ.\nНажмите здесь, если обнаружили ошибку.</string>
|
||||
<string name="initial_message_change_access_code_body">Чтобы изменить код доступа, приложите карту или кольцо как показано выше и не убирайте до окончания операции</string>
|
||||
<string name="initial_message_change_passcode_body">Чтобы изменить пароль, приложите карту как показано выше и не убирайте до окончания операции</string>
|
||||
<string name="initial_message_create_wallet_body">Чтобы создать кошелек, приложите карту как показано выше и не убирайте до окончания операции</string>
|
||||
|
|
@ -608,7 +608,7 @@
|
|||
</plurals>
|
||||
<string name="reset_card_to_factory_button_title">Сбросить карту</string>
|
||||
<string name="reset_card_to_factory_condition_1">Я понимаю, что после выполнения этого действия у меня больше не будет доступа к текущему кошельку</string>
|
||||
<string name="reset_card_to_factory_condition_2">Я понимаю, что не смогу этой картой восстановить пароль на остальных картах этого кошелька, если я его забуду</string>
|
||||
<string name="reset_card_to_factory_condition_2">Я понимаю, что не смогу использовать эту карту для восстановления кода доступа на других картах текущего кошелька</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты или кольца. Вы не сможете восстановить текущий кошелек или использовать данную карту или кольцо для восстановления кода доступа.</string>
|
||||
<string name="reset_card_without_backup_to_factory_message">Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты или кольца. Вы не сможете восстановить текущий кошелек.</string>
|
||||
<string name="ring_promo_text">Владельцам колец — 3 обмена без комиссии на Changelly до 15.11!</string>
|
||||
|
|
@ -626,7 +626,7 @@
|
|||
<string name="save_user_wallet_agreement_notice">Обратите внимание, что для совершения транзакции с вашими средствами по-прежнему потребуется ваша карта или кольцо</string>
|
||||
<string name="scan_card_settings_button">Сканировать</string>
|
||||
<string name="scan_card_settings_message">Отсканируйте карту или кольцо, чтобы изменить ее настройки. Изменения затронут только ту карту или кольцо, которые вы отсканировали, и не повлияют на другие устройства, привязанные к вашему кошельку.</string>
|
||||
<string name="scan_card_settings_title">Приготовьте свой Tangem</string>
|
||||
<string name="scan_card_settings_title">Приготовьте свой Tangem!</string>
|
||||
<string name="send_additional_field_already_included">Уже содержится во введенном адресе</string>
|
||||
<string name="send_alert_fee_too_high_text">Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна.</string>
|
||||
<string name="send_alert_fee_too_low_text">Вы указали комиссию ниже рекомендуемой, это может привести к задержке исполнения вашей транзакции. Продолжить?</string>
|
||||
|
|
@ -702,7 +702,7 @@
|
|||
<string name="send_transaction_success">Транзакция успешно подписана и отправлена в блокчейн. Баланс будет обновлен через некоторое время</string>
|
||||
<string name="send_tron_account_activation_error">%1$s — это монета в сети Tron. Чтобы рассчитать комиссию и совершить транзакцию, вам необходимо внести немного Tron (TRX) на свой адрес.</string>
|
||||
<string name="sent_transaction_sent_title">Транзакция отправлена</string>
|
||||
<string name="settings_card_settings_footer">Подготовьтесь к сканированию кольцо или карту, которую вы хотите настроить.</string>
|
||||
<string name="settings_card_settings_footer">Подготовьтесь к сканированию кольца или карты, которую вы хотите настроить.</string>
|
||||
<string name="settings_forget_wallet">Забыть кошелек</string>
|
||||
<string name="settings_forget_wallet_footer">Это приведет к удалению кошелька из приложения. Сам кошелек можно добавить снова.</string>
|
||||
<string name="settings_wallet_name_title">Имя</string>
|
||||
|
|
@ -960,7 +960,7 @@
|
|||
<string name="warning_express_too_maximum_amount_title">Сумма для обмена должна быть не более %s</string>
|
||||
<string name="warning_express_too_minimal_amount_title">Сумма для обмена должна быть не менее %s</string>
|
||||
<string name="warning_express_wrong_amount_description">Пожалуйста, измените сумму для обмена</string>
|
||||
<string name="warning_failed_to_verify_card_message">Возможно, данная карта - образец или подделка</string>
|
||||
<string name="warning_failed_to_verify_card_message">Возможно, данная карта является образцом или подделкой</string>
|
||||
<string name="warning_failed_to_verify_card_title">Ошибка проверки подлинности</string>
|
||||
<string name="warning_hedera_missing_token_association_button_title">Ассоциировать</string>
|
||||
<string name="warning_hedera_missing_token_association_message">Этот токен должен быть ассоциирован с вашей учетной записью Hedera, прежде чем вы сможете его принять. Стоимость ассоциации ~%1$s %2$s </string>
|
||||
|
|
@ -970,7 +970,7 @@
|
|||
<string name="warning_low_signatures_message">На этой карте осталось всего %s подписей. Вам следует вывести все ваши средства.</string>
|
||||
<string name="warning_low_signatures_title">Малое количество подписей</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Токены на разных сетях могут иметь разные адреса. Пожалуйста, убедитесь при переводе средств, что ваш адрес соответствует сети.</string>
|
||||
<string name="warning_matic_migration_message">Токен MATIC мигрирует на POL. Однако крайний срок не установлен, и MATIC пока не устарел. Вы можете спокойно продолжать использовать токен MATIC или воспользоваться биржами, чтобы обменять его на POL.</string>
|
||||
<string name="warning_matic_migration_message">Токен MATIC мигрирует на POL. Однако крайний срок не установлен, и MATIC пока не устарел. Вы можете спокойно продолжать использовать токен MATIC или обменять его на POL.</string>
|
||||
<string name="warning_matic_migration_title">Миграция MATIC в POL</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="one">Используйте вашу карту или кольцо, чтобы получить адрес для %d сети</item>
|
||||
|
|
|
|||
|
|
@ -967,7 +967,7 @@
|
|||
<string name="warning_low_signatures_message">На цій картці залишається лише %s підписів. Ви повинні вивести всі свої кошти.</string>
|
||||
<string name="warning_low_signatures_title">Низька кількість підписів</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Токени в різних мережах можуть мати різні адреси. Переконайтеся, що ваша адреса відповідає мережі, коли переказуєте кошти.</string>
|
||||
<string name="warning_matic_migration_message">Токен MATIC мігрує до POL. Однак кінцевого терміну не встановлено і MATIC ще не застарілий. Ви можете безпечно продовжувати використовувати токен MATIC або скористатися біржами, щоб обміняти його на POL.</string>
|
||||
<string name="warning_matic_migration_message">Токен MATIC мігрує до POL. Однак кінцевого терміну не встановлено і MATIC ще не застарілий. Ви можете безпечно продовжувати використовувати токен MATIC або обміняти його на POL.</string>
|
||||
<string name="warning_matic_migration_title">Міграція MATIC у POL</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="one">Використовуйте вашу картку, щоб отримати адресу для %d мережі</item>
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@
|
|||
<string name="details_manage_security_access_code">Access code</string>
|
||||
<string name="details_manage_security_access_code_description">You will have to submit the correct access code before scanning the card</string>
|
||||
<string name="details_manage_security_long_tap">Long Tap</string>
|
||||
<string name="details_manage_security_long_tap_description">This mechanism protects against proximity attacks on a card or ring. It will enforce a delay between reception and execution of a command. </string>
|
||||
<string name="details_manage_security_long_tap_description">This mechanism protects against proximity attacks on a card or ring. It will enforce a delay between reception and execution of a command.</string>
|
||||
<string name="details_manage_security_passcode">Passcode</string>
|
||||
<string name="details_manage_security_passcode_description">Before executing any command entailing a change of the card state, you will have to enter the passcode.</string>
|
||||
<string name="details_referral_title">Referral program</string>
|
||||
|
|
@ -307,7 +307,7 @@
|
|||
<string name="give_permission_unlimited">Unlimited</string>
|
||||
<string name="home_button_order">Order Tangem</string>
|
||||
<string name="home_button_scan">Scan Tangem</string>
|
||||
<string name="information_generated_with_ai">This information was generated with AI</string>
|
||||
<string name="information_generated_with_ai">This information was generated with AI.\nTap here, If you find any errors.</string>
|
||||
<string name="initial_message_change_access_code_body">To change the access code tap the card or ring as shown above and do not remove until the end of the operation</string>
|
||||
<string name="initial_message_change_passcode_body">To change the passcode tap the card as shown above and do not remove until the end of the operation</string>
|
||||
<string name="initial_message_create_wallet_body">To create the wallet tap the card as shown above and do not remove until the end of the operation</string>
|
||||
|
|
@ -458,7 +458,7 @@
|
|||
<string name="onboarding_access_code_feature_1_title">Protect</string>
|
||||
<string name="onboarding_access_code_feature_2_description">Set an individual access code for each card or ring later.</string>
|
||||
<string name="onboarding_access_code_feature_2_title">Personalize</string>
|
||||
<string name="onboarding_access_code_feature_3_description">Restore the access code with a linked card or ring. Don`t keep all your devices in one place.</string>
|
||||
<string name="onboarding_access_code_feature_3_description">Restore the access code with a linked card or ring. Don\'t keep all your devices in one place.</string>
|
||||
<string name="onboarding_access_code_feature_3_title">Restore</string>
|
||||
<string name="onboarding_access_code_hint">Choose any word, phrase, or number you want as your access code</string>
|
||||
<string name="onboarding_access_code_intro_title">Create Access Code</string>
|
||||
|
|
@ -469,7 +469,7 @@
|
|||
<string name="onboarding_activation_error_message">Please repeat the operation. The card will be reset to factory settings.</string>
|
||||
<string name="onboarding_activation_error_title">Activation error</string>
|
||||
<string name="onboarding_add_tokens">Add tokens</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">You\'ve added one backup card or ring. When backup process is finished you can\'t add more backup devices. If you have one more card or ring, add it to backup. Do you like to continue the backup process?</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">You\'ve added one backup card or ring. When backup process is finished you can\'t add more backup devices. If you have one more card or ring, add it to the backup. Would you like to continue the backup process?</string>
|
||||
<string name="onboarding_backup_exit_warning">The backup process is partly complete. You can\'t exit it now.</string>
|
||||
<string name="onboarding_bottom_sheet_passphrase_description">The passphrase is an advanced security feature that crypto wallets use. It adds an extra word or phrase of your own choosing to your already existing recovery phrase to unlock a brand-new set of addresses.</string>
|
||||
<string name="onboarding_button_add_backup_card">Add a card or ring</string>
|
||||
|
|
@ -785,7 +785,7 @@
|
|||
<string name="story_awe_title">Revolutionary Hardware Wallet</string>
|
||||
<string name="story_backup_description">Up to 3 physical cards or rings to one wallet</string>
|
||||
<string name="story_backup_title">Ultra Secure Backup</string>
|
||||
<string name="story_currencies_description">A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card or ring</string>
|
||||
<string name="story_currencies_description">A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously — all in one card or ring</string>
|
||||
<string name="story_currencies_title">Thousands of Currencies</string>
|
||||
<string name="story_finish_description">Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card or ring to your phone when you need your crypto.</string>
|
||||
<string name="story_finish_title">The Wallet for Everyone</string>
|
||||
|
|
@ -955,7 +955,7 @@
|
|||
<string name="warning_low_signatures_message">Only %s signatures are left on this card. You must withdraw all of your funds.</string>
|
||||
<string name="warning_low_signatures_title">Low signature count</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Tokens on different networks can have different addresses. Double-check that your address matches the network when you transfer funds.</string>
|
||||
<string name="warning_matic_migration_message">MATIC is being migrated to POL. However there is no deadline set and MATIC isn\'t being deprecated yet. You can safely continue using MATIC token or use exchanges to swap it for POL.</string>
|
||||
<string name="warning_matic_migration_message">MATIC is being migrated to POL. However, there is no deadline set and MATIC isn\'t being deprecated yet. You can safely continue using MATIC token or swap it for POL.</string>
|
||||
<string name="warning_matic_migration_title">MATIC to POL Migration</string>
|
||||
<plurals name="warning_missing_derivation_message">
|
||||
<item quantity="one">Use your card or ring to get an address for %d network</item>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
package com.tangem.core.ui.components
|
||||
|
||||
import androidx.compose.animation.core.AnimationSpec
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
fun Modifier.edgeFade(
|
||||
vararg positions: FadePosition,
|
||||
size: Dp,
|
||||
isVisible: Boolean = true,
|
||||
animationSpec: AnimationSpec<Dp>? = null,
|
||||
color: Color = TangemTheme.colors.background.secondary,
|
||||
): Modifier = composed {
|
||||
require(value = size > 0.dp) {
|
||||
"Size must be greater than '0'"
|
||||
}
|
||||
val animatedSize = animationSpec?.let {
|
||||
animateDpAsState(
|
||||
targetValue = if (isVisible) size else 0.dp,
|
||||
animationSpec = it,
|
||||
label = "Edge fade width",
|
||||
)
|
||||
}
|
||||
|
||||
drawWithContent {
|
||||
drawContent()
|
||||
|
||||
positions.forEach { side ->
|
||||
val (start, end) = this.size.getFadeOffsets(side)
|
||||
|
||||
val staticSizePx = if (isVisible) size.toPx() else 0f
|
||||
val sizePx = animatedSize?.value?.toPx() ?: staticSizePx
|
||||
|
||||
val fraction = when (side) {
|
||||
FadePosition.LEFT, FadePosition.RIGHT -> sizePx / this.size.width
|
||||
FadePosition.BOTTOM, FadePosition.TOP -> sizePx / this.size.height
|
||||
}
|
||||
|
||||
drawRect(
|
||||
brush = Brush.linearGradient(
|
||||
0f to color,
|
||||
fraction to Color.Transparent,
|
||||
start = start,
|
||||
end = end,
|
||||
),
|
||||
size = this.size,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Modifier.bottomFade(
|
||||
height: Dp = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() } + 96.dp,
|
||||
color: Color = TangemTheme.colors.background.secondary,
|
||||
): Modifier = edgeFade(
|
||||
FadePosition.BOTTOM,
|
||||
size = height,
|
||||
color = color,
|
||||
)
|
||||
|
||||
enum class FadePosition {
|
||||
TOP, BOTTOM, LEFT, RIGHT;
|
||||
}
|
||||
|
||||
@Stable
|
||||
private fun Size.getFadeOffsets(position: FadePosition): Pair<Offset, Offset> {
|
||||
return when (position) {
|
||||
FadePosition.LEFT -> Offset.Zero to Offset(width, 0f)
|
||||
FadePosition.RIGHT -> Offset(width, y = 0f) to Offset.Zero
|
||||
FadePosition.BOTTOM -> Offset(x = 0f, height) to Offset.Zero
|
||||
FadePosition.TOP -> Offset.Zero to Offset(x = 0f, height)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package com.tangem.core.ui.components.audits
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
/**
|
||||
* Audit label component
|
||||
*
|
||||
* @param state state
|
||||
* @param modifier modifier
|
||||
*
|
||||
* @see <a href="https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=3401-3635&t=kjnj9RhYUOwbO1hn-4">Figma</a>
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun AuditLabel(state: AuditLabelUM, modifier: Modifier = Modifier) {
|
||||
AuditLabelInternal(
|
||||
textReference = state.text,
|
||||
textColor = getColorByType(state.type),
|
||||
backgroundColor = getColorByType(state.type).copy(alpha = 0.1f),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AuditLabelInternal(
|
||||
textReference: TextReference,
|
||||
textColor: Color,
|
||||
backgroundColor: Color,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.background(
|
||||
color = backgroundColor,
|
||||
shape = TangemTheme.shapes.roundedCornersSmall2,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = textReference.resolveReference(),
|
||||
style = TangemTheme.typography.caption1,
|
||||
color = textColor,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
private fun getColorByType(type: AuditLabelUM.Type): Color {
|
||||
return when (type) {
|
||||
AuditLabelUM.Type.Prohibition -> TangemTheme.colors.text.warning
|
||||
AuditLabelUM.Type.Warning -> TangemTheme.colors.text.attention
|
||||
AuditLabelUM.Type.Permit -> TangemTheme.colors.text.accent
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_AuditLabel(@PreviewParameter(AuditLabelUMProvider::class) state: AuditLabelUM) {
|
||||
TangemThemePreview {
|
||||
AuditLabel(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
private class AuditLabelUMProvider : CollectionPreviewParameterProvider<AuditLabelUM>(
|
||||
collection = AuditLabelUM.Type.entries.map { type ->
|
||||
AuditLabelUM(
|
||||
text = TextReference.Str(value = type.name),
|
||||
type = type,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.core.ui.components.audits
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
/**
|
||||
* Audit label component UI model
|
||||
*
|
||||
* @property text text reference
|
||||
* @property type type of label
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class AuditLabelUM(val text: TextReference, val type: Type) {
|
||||
|
||||
enum class Type {
|
||||
|
||||
/** Red. Like, "risky" */
|
||||
Prohibition,
|
||||
|
||||
/** Yellow. Like, "caution" */
|
||||
Warning,
|
||||
|
||||
/** Blue. Like, "trusted" */
|
||||
Permit,
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.rows.CornersToRound
|
||||
import com.tangem.core.ui.components.rows.RoundableCornersRow
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
|
|
@ -63,7 +62,8 @@ fun LazyListScope.roundedListWithDividersItems(
|
|||
InitialInfoContentRow(
|
||||
startText = row.startText.resolveReference(),
|
||||
endText = row.endText.orMaskWithStars(hideEndText && row.isEndTextHideable).resolveReference(),
|
||||
cornersToRound = getCornersToRound(index, rows.size),
|
||||
currentIndex = index,
|
||||
lastIndex = rows.lastIndex,
|
||||
iconClick = row.iconClick,
|
||||
endTextColor = if (row.isEndTextHighlighted) {
|
||||
TangemTheme.colors.text.accent
|
||||
|
|
@ -85,7 +85,8 @@ fun LazyListScope.roundedListWithDividersItems(
|
|||
private fun InitialInfoContentRow(
|
||||
startText: String,
|
||||
endText: String,
|
||||
cornersToRound: CornersToRound,
|
||||
currentIndex: Int,
|
||||
lastIndex: Int,
|
||||
showDivider: Boolean,
|
||||
endTextColor: Color = TangemTheme.colors.text.tertiary,
|
||||
iconClick: (() -> Unit)? = null,
|
||||
|
|
@ -98,7 +99,8 @@ private fun InitialInfoContentRow(
|
|||
endText = endText,
|
||||
endTextColor = endTextColor,
|
||||
endTextStyle = TangemTheme.typography.body2,
|
||||
cornersToRound = cornersToRound,
|
||||
currentIndex = currentIndex,
|
||||
lastIndex = lastIndex,
|
||||
iconResId = R.drawable.ic_information_24,
|
||||
iconClick = iconClick,
|
||||
)
|
||||
|
|
@ -121,14 +123,6 @@ fun RoundedListDivider(modifier: Modifier = Modifier) {
|
|||
)
|
||||
}
|
||||
|
||||
private fun getCornersToRound(currentIndex: Int, listSize: Int): CornersToRound {
|
||||
return when (currentIndex) {
|
||||
0 -> CornersToRound.TOP_2
|
||||
listSize - 1 -> CornersToRound.BOTTOM_2
|
||||
else -> CornersToRound.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
data class RoundedListWithDividersItemData(
|
||||
val id: Int,
|
||||
val startText: TextReference,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ fun Notification(
|
|||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
subtitleColor = subtitleColor,
|
||||
isClickableComponent = isEnabled && config.onClick != null,
|
||||
showArrowIcon = isEnabled && config.showArrowIcon,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -130,7 +130,7 @@ private fun MainContent(
|
|||
title: TextReference?,
|
||||
subtitle: TextReference,
|
||||
subtitleColor: Color,
|
||||
isClickableComponent: Boolean,
|
||||
showArrowIcon: Boolean,
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
|
|
@ -145,7 +145,7 @@ private fun MainContent(
|
|||
|
||||
TextsBlock(title = title, subtitle = subtitle, subtitleColor = subtitleColor)
|
||||
|
||||
if (isClickableComponent) {
|
||||
if (showArrowIcon) {
|
||||
SpacerWMax()
|
||||
|
||||
Icon(
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ data class NotificationConfig(
|
|||
val buttonsState: ButtonsState? = null,
|
||||
val onClick: (() -> Unit)? = null,
|
||||
val onCloseClick: (() -> Unit)? = null,
|
||||
val showArrowIcon: Boolean = onClick != null,
|
||||
) {
|
||||
|
||||
sealed class ButtonsState {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import androidx.compose.foundation.background
|
|||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -20,9 +19,8 @@ import androidx.compose.ui.text.TextStyle
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
|
|
@ -35,12 +33,18 @@ fun RoundableCornersRow(
|
|||
endText: String,
|
||||
endTextColor: Color,
|
||||
endTextStyle: TextStyle,
|
||||
cornersToRound: CornersToRound,
|
||||
currentIndex: Int,
|
||||
lastIndex: Int,
|
||||
iconResId: Int? = null,
|
||||
iconClick: (() -> Unit)? = null,
|
||||
) {
|
||||
Surface(
|
||||
shape = cornersToRound.getShape(),
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = currentIndex,
|
||||
lastIndex = lastIndex,
|
||||
addDefaultPadding = false,
|
||||
),
|
||||
color = TangemTheme.colors.background.action,
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -86,26 +90,6 @@ fun RoundableCornersRow(
|
|||
}
|
||||
}
|
||||
|
||||
enum class CornersToRound {
|
||||
|
||||
ALL_4,
|
||||
TOP_2,
|
||||
BOTTOM_2,
|
||||
ZERO,
|
||||
;
|
||||
|
||||
@Suppress("TopLevelComposableFunctions")
|
||||
@Composable
|
||||
fun getShape(radius: Dp = TangemTheme.dimens.radius12): RoundedCornerShape {
|
||||
return when (this) {
|
||||
ALL_4 -> RoundedCornerShape(radius)
|
||||
TOP_2 -> RoundedCornerShape(topStart = radius, topEnd = radius)
|
||||
BOTTOM_2 -> RoundedCornerShape(bottomStart = radius, bottomEnd = radius)
|
||||
ZERO -> RoundedCornerShape(0.dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
|
|
@ -121,7 +105,8 @@ private fun Preview_RoundableCornersRow(
|
|||
endText = previewData.endText,
|
||||
endTextColor = TangemTheme.colors.text.primary1,
|
||||
endTextStyle = TangemTheme.typography.subtitle2,
|
||||
cornersToRound = previewData.cornersToRound,
|
||||
currentIndex = previewData.currentIndex,
|
||||
lastIndex = previewData.lastIndex,
|
||||
iconResId = previewData.iconResId,
|
||||
)
|
||||
}
|
||||
|
|
@ -131,7 +116,8 @@ private fun Preview_RoundableCornersRow(
|
|||
private data class RoundableCornersRowPreviewData(
|
||||
val startText: String,
|
||||
val endText: String,
|
||||
val cornersToRound: CornersToRound,
|
||||
val currentIndex: Int,
|
||||
val lastIndex: Int,
|
||||
val iconResId: Int? = null,
|
||||
)
|
||||
|
||||
|
|
@ -140,18 +126,20 @@ private class RoundableCornersRowDataProvider :
|
|||
|
||||
override val values: Sequence<RoundableCornersRowPreviewData>
|
||||
get() = sequenceOf(
|
||||
getPreviewData(cornersToRound = CornersToRound.ZERO),
|
||||
getPreviewData(cornersToRound = CornersToRound.TOP_2),
|
||||
getPreviewData(cornersToRound = CornersToRound.BOTTOM_2),
|
||||
getPreviewData(cornersToRound = CornersToRound.ZERO, iconResId = R.drawable.ic_alert_24),
|
||||
getPreviewData(cornersToRound = CornersToRound.TOP_2, iconResId = R.drawable.ic_alert_24),
|
||||
getPreviewData(cornersToRound = CornersToRound.BOTTOM_2, iconResId = R.drawable.ic_alert_24),
|
||||
getPreviewData(currentIndex = 1, lastIndex = 2),
|
||||
getPreviewData(currentIndex = 0, lastIndex = 2),
|
||||
getPreviewData(currentIndex = 2, lastIndex = 2),
|
||||
getPreviewData(currentIndex = 1, lastIndex = 2, iconResId = R.drawable.ic_alert_24),
|
||||
getPreviewData(currentIndex = 0, lastIndex = 2, iconResId = R.drawable.ic_alert_24),
|
||||
getPreviewData(currentIndex = 2, lastIndex = 2, iconResId = R.drawable.ic_alert_24),
|
||||
)
|
||||
|
||||
private fun getPreviewData(cornersToRound: CornersToRound, iconResId: Int? = null) = RoundableCornersRowPreviewData(
|
||||
startText = "startText",
|
||||
endText = "endText",
|
||||
cornersToRound = cornersToRound,
|
||||
iconResId = iconResId,
|
||||
)
|
||||
private fun getPreviewData(currentIndex: Int, lastIndex: Int, iconResId: Int? = null) =
|
||||
RoundableCornersRowPreviewData(
|
||||
startText = "startText",
|
||||
endText = "endText",
|
||||
currentIndex = currentIndex,
|
||||
lastIndex = lastIndex,
|
||||
iconResId = iconResId,
|
||||
)
|
||||
}
|
||||
|
|
@ -17,11 +17,13 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.audits.AuditLabelUM
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.components.token.internal.*
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.rememberHapticFeedback
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -122,7 +124,7 @@ fun TokenItem(
|
|||
)
|
||||
|
||||
TokenCryptoAmount(
|
||||
state = state.cryptoAmountState,
|
||||
state = state.subtitle2State,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = Modifier.layoutId(layoutId = LayoutId.CRYPTO_AMOUNT),
|
||||
)
|
||||
|
|
@ -461,7 +463,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
|
|||
text = "3213123123321312312312312312 $",
|
||||
hasStaked = true,
|
||||
),
|
||||
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "5,4123123213123123123123123123 MATIC"),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "5,4123123213123123123123123123 MATIC"),
|
||||
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
|
||||
price = "312 USD",
|
||||
priceChangePercent = "42.0%",
|
||||
|
|
@ -500,14 +502,33 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
|
|||
id = UUID.randomUUID().toString(),
|
||||
iconState = tokenIconState,
|
||||
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
|
||||
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "3 172,14 $"),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "3 172,14 $"),
|
||||
),
|
||||
TokenItemState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
iconState = tokenIconState,
|
||||
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "321 $", hasStaked = false),
|
||||
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "5,412 MATIC"),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "5,412 MATIC"),
|
||||
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
|
||||
price = "312 USD",
|
||||
priceChangePercent = "2.0%",
|
||||
type = PriceChangeType.UP,
|
||||
),
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
),
|
||||
TokenItemState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
iconState = tokenIconState,
|
||||
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "321 $", hasStaked = false),
|
||||
subtitle2State = TokenItemState.Subtitle2State.LabelContent(
|
||||
auditLabelUM = AuditLabelUM(
|
||||
text = TextReference.Str(value = "Trusted"),
|
||||
type = AuditLabelUM.Type.Permit,
|
||||
),
|
||||
),
|
||||
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
|
||||
price = "312 USD",
|
||||
priceChangePercent = "2.0%",
|
||||
|
|
@ -573,7 +594,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
|
|||
iconState = coinIconState,
|
||||
titleState = TokenItemState.TitleState.Content(text = "Polygon", hasPending = true),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "321 $", hasStaked = true),
|
||||
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "5,412 MATIC"),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "5,412 MATIC"),
|
||||
subtitleState = TokenItemState.SubtitleState.Unknown,
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.audits.AuditLabel
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.CryptoAmountState as TokenCryptoAmountState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.Subtitle2State as TokenCryptoAmountState
|
||||
|
||||
@Composable
|
||||
internal fun TokenCryptoAmount(
|
||||
|
|
@ -21,12 +23,15 @@ internal fun TokenCryptoAmount(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when (state) {
|
||||
is TokenCryptoAmountState.Content -> {
|
||||
is TokenCryptoAmountState.TextContent -> {
|
||||
CryptoAmountText(
|
||||
amount = state.text.orMaskWithStars(isBalanceHidden),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
is TokenItemState.Subtitle2State.LabelContent -> {
|
||||
AuditLabel(state = state.auditLabelUM, modifier = modifier)
|
||||
}
|
||||
is TokenCryptoAmountState.Unreachable -> {
|
||||
CryptoAmountText(amount = stringResource(id = R.string.common_unreachable), modifier = modifier)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.core.ui.components.token.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.audits.AuditLabelUM
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
|
||||
|
|
@ -17,14 +18,17 @@ sealed class TokenItemState {
|
|||
/** Token title state (in one row with [fiatAmountState]) */
|
||||
abstract val titleState: TitleState
|
||||
|
||||
/** Token subtitle state (under [titleState] and in one row with [cryptoAmountState]) */
|
||||
/** Token subtitle state (under [titleState] and in one row with [subtitle2State]) */
|
||||
abstract val subtitleState: SubtitleState?
|
||||
|
||||
/** Token fiat amount state (in one row with [titleState]) */
|
||||
abstract val fiatAmountState: FiatAmountState?
|
||||
|
||||
/** Token crypto amount state (under [fiatAmountState] and in one row with [subtitleState]) */
|
||||
abstract val cryptoAmountState: CryptoAmountState?
|
||||
/**
|
||||
* Second subtitle state (under [fiatAmountState] and in one row with [subtitleState]).
|
||||
* Example, token crypto amount.
|
||||
*/
|
||||
abstract val subtitle2State: Subtitle2State?
|
||||
|
||||
/** Callback which will be called when an item is clicked */
|
||||
abstract val onItemClick: (() -> Unit)?
|
||||
|
|
@ -42,12 +46,12 @@ sealed class TokenItemState {
|
|||
*/
|
||||
data class Loading(
|
||||
override val id: String,
|
||||
override val iconState: CurrencyIconState,
|
||||
override val titleState: TitleState.Content,
|
||||
override val iconState: CurrencyIconState = CurrencyIconState.Loading,
|
||||
override val titleState: TitleState = TitleState.Loading,
|
||||
override val subtitleState: SubtitleState = SubtitleState.Loading,
|
||||
) : TokenItemState() {
|
||||
override val fiatAmountState: FiatAmountState = FiatAmountState.Loading
|
||||
override val cryptoAmountState: CryptoAmountState = CryptoAmountState.Loading
|
||||
override val subtitle2State: Subtitle2State = Subtitle2State.Loading
|
||||
override val onItemClick: (() -> Unit)? = null
|
||||
override val onItemLongClick: (() -> Unit)? = null
|
||||
}
|
||||
|
|
@ -62,7 +66,7 @@ sealed class TokenItemState {
|
|||
override val titleState: TitleState = TitleState.Locked
|
||||
override val subtitleState: SubtitleState = SubtitleState.Locked
|
||||
override val fiatAmountState: FiatAmountState = FiatAmountState.Locked
|
||||
override val cryptoAmountState: CryptoAmountState = CryptoAmountState.Locked
|
||||
override val subtitle2State: Subtitle2State = Subtitle2State.Locked
|
||||
override val onItemClick: (() -> Unit)? = null
|
||||
override val onItemLongClick: (() -> Unit)? = null
|
||||
}
|
||||
|
|
@ -75,7 +79,7 @@ sealed class TokenItemState {
|
|||
* @property titleState token title
|
||||
* @property subtitleState token subtitle
|
||||
* @property fiatAmountState token fiat amount
|
||||
* @property cryptoAmountState token crypto amount
|
||||
* @property subtitle2State token crypto amount
|
||||
* @property onItemClick callback which will be called when an item is clicked
|
||||
* @property onItemLongClick callback which will be called when an item is long clicked
|
||||
*/
|
||||
|
|
@ -85,7 +89,7 @@ sealed class TokenItemState {
|
|||
override val titleState: TitleState,
|
||||
override val subtitleState: SubtitleState,
|
||||
override val fiatAmountState: FiatAmountState,
|
||||
override val cryptoAmountState: CryptoAmountState.Content,
|
||||
override val subtitle2State: Subtitle2State,
|
||||
override val onItemClick: (() -> Unit)?,
|
||||
override val onItemLongClick: (() -> Unit)?,
|
||||
) : TokenItemState()
|
||||
|
|
@ -96,13 +100,13 @@ sealed class TokenItemState {
|
|||
* @property id unique id
|
||||
* @property iconState token icon state
|
||||
* @property titleState token title
|
||||
* @property cryptoAmountState token crypto amount
|
||||
* @property subtitle2State token crypto amount
|
||||
*/
|
||||
data class Draggable(
|
||||
override val id: String,
|
||||
override val iconState: CurrencyIconState,
|
||||
override val titleState: TitleState,
|
||||
override val cryptoAmountState: CryptoAmountState,
|
||||
override val subtitle2State: Subtitle2State,
|
||||
) : TokenItemState() {
|
||||
override val subtitleState: SubtitleState? = null
|
||||
override val fiatAmountState: FiatAmountState? = null
|
||||
|
|
@ -129,7 +133,7 @@ sealed class TokenItemState {
|
|||
override val onItemLongClick: (() -> Unit)?,
|
||||
) : TokenItemState() {
|
||||
override val fiatAmountState: FiatAmountState? = null
|
||||
override val cryptoAmountState: CryptoAmountState? = null
|
||||
override val subtitle2State: Subtitle2State? = null
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -149,7 +153,7 @@ sealed class TokenItemState {
|
|||
override val onItemLongClick: (() -> Unit)?,
|
||||
) : TokenItemState() {
|
||||
override val fiatAmountState: FiatAmountState? = null
|
||||
override val cryptoAmountState: CryptoAmountState? = null
|
||||
override val subtitle2State: Subtitle2State? = null
|
||||
override val onItemClick: (() -> Unit)? = null
|
||||
}
|
||||
|
||||
|
|
@ -194,13 +198,16 @@ sealed class TokenItemState {
|
|||
}
|
||||
|
||||
@Immutable
|
||||
sealed class CryptoAmountState {
|
||||
data class Content(val text: String) : CryptoAmountState()
|
||||
sealed class Subtitle2State {
|
||||
|
||||
data object Unreachable : CryptoAmountState()
|
||||
data class TextContent(val text: String) : Subtitle2State()
|
||||
|
||||
data object Loading : CryptoAmountState()
|
||||
data class LabelContent(val auditLabelUM: AuditLabelUM) : Subtitle2State()
|
||||
|
||||
data object Locked : CryptoAmountState()
|
||||
data object Unreachable : Subtitle2State()
|
||||
|
||||
data object Loading : Subtitle2State()
|
||||
|
||||
data object Locked : Subtitle2State()
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +76,9 @@ fun getActiveIconRes(blockchainId: String): Int {
|
|||
"sei", "sei/test" -> R.drawable.img_sei_22
|
||||
"internet-computer" -> R.drawable.img_icp_22
|
||||
"sui", "sui/test" -> R.drawable.img_sui_22
|
||||
"energy-web-chain", "energy-web-chain/test" -> R.drawable.img_energy_web_22
|
||||
"energy-web-x", "energy-web-x/test" -> R.drawable.img_energy_web_22
|
||||
"core", "core/test" -> R.drawable.img_core_22
|
||||
else -> R.drawable.ic_alert_24
|
||||
}
|
||||
}
|
||||
|
|
@ -153,6 +156,9 @@ fun getActiveIconResByNetworkId(networkId: String): Int {
|
|||
"sei", "sei/test" -> R.drawable.img_sei_22
|
||||
"internet-computer" -> R.drawable.img_icp_22
|
||||
"sui", "sui/test" -> R.drawable.img_sui_22
|
||||
"energy-web-chain", "energy-web-chain/test" -> R.drawable.img_energy_web_22
|
||||
"energy-web-x", "energy-web-x/test" -> R.drawable.img_energy_web_22
|
||||
"core", "core/test" -> R.drawable.img_core_22
|
||||
else -> R.drawable.ic_alert_24
|
||||
}
|
||||
}
|
||||
|
|
@ -227,6 +233,9 @@ fun getActiveIconResByCoinId(coinId: String): Int {
|
|||
"sei", "sei/test" -> R.drawable.img_sei_22
|
||||
"internet-computer" -> R.drawable.img_icp_22
|
||||
"sui", "sui/test" -> R.drawable.img_sui_22
|
||||
"energy-web-chain", "energy-web-chain/test" -> R.drawable.img_energy_web_22
|
||||
"energy-web-x", "energy-web-x/test" -> R.drawable.img_energy_web_22
|
||||
"core", "core/test" -> R.drawable.img_core_22
|
||||
else -> R.drawable.ic_alert_24
|
||||
}
|
||||
}
|
||||
|
|
@ -304,6 +313,9 @@ fun getGreyedOutIconRes(blockchainId: String): Int {
|
|||
"sei", "sei/test" -> R.drawable.ic_sei_22
|
||||
"internet-computer" -> R.drawable.ic_icp_22
|
||||
"sui", "sui/test" -> R.drawable.ic_sui_22
|
||||
"energy-web-chain", "energy-web-chain/test" -> R.drawable.ic_energy_web_22
|
||||
"energy-web-x", "energy-web-x/test" -> R.drawable.ic_energy_web_22
|
||||
"core", "core/test" -> R.drawable.ic_core_22
|
||||
else -> R.drawable.ic_alert_24
|
||||
}
|
||||
}
|
||||
|
|
@ -381,6 +393,9 @@ fun getGreyedOutIconResByNetworkId(networkId: String): Int {
|
|||
"sei", "sei/test" -> R.drawable.ic_sei_22
|
||||
"internet-computer" -> R.drawable.ic_icp_22
|
||||
"sui", "sui/test" -> R.drawable.ic_sui_22
|
||||
"energy-web-chain", "energy-web-chain/test" -> R.drawable.ic_energy_web_22
|
||||
"energy-web-x", "energy-web-x/test" -> R.drawable.ic_energy_web_22
|
||||
"core", "core/test" -> R.drawable.ic_core_22
|
||||
else -> R.drawable.ic_alert_24
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ object DateTimeFormatters {
|
|||
.withLocale(Locale.getDefault())
|
||||
} else {
|
||||
DateTimeFormatterBuilder()
|
||||
.appendHourOfDay(1)
|
||||
.appendHourOfDay(2)
|
||||
.appendLiteral(':')
|
||||
.appendMinuteOfHour(2)
|
||||
.toFormatter()
|
||||
|
|
|
|||
10
core/ui/src/main/res/drawable/ic_core_22.xml
Normal file
10
core/ui/src/main/res/drawable/ic_core_22.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<path
|
||||
android:pathData="M11,4.66L5.501,7.83V14.17L11,17.34L16.499,14.17V7.83L11,4.66ZM11.231,3.062C11.088,2.979 10.912,2.979 10.769,3.062L4.231,6.831C4.088,6.914 4,7.066 4,7.231V14.769C4,14.934 4.088,15.086 4.231,15.169L10.769,18.938C10.912,19.021 11.088,19.021 11.231,18.938L17.769,15.169C17.912,15.086 18,14.934 18,14.769V7.231C18,7.066 17.912,6.914 17.769,6.831L11.231,3.062ZM11,6.956L7.493,8.978V13.022L10.977,15.031C10.991,15.039 11,15.054 11,15.071V15.763C11,15.798 10.962,15.821 10.931,15.803L6.973,13.521C6.866,13.46 6.8,13.345 6.8,13.222V8.778C6.8,8.655 6.866,8.541 6.973,8.479L10.827,6.257C10.934,6.195 11.066,6.195 11.173,6.257L15.146,8.539C15.177,8.557 15.177,8.601 15.147,8.619C14.98,8.718 14.872,8.777 14.729,8.856L14.729,8.856L14.728,8.856C14.67,8.888 14.606,8.923 14.53,8.965C14.516,8.973 14.498,8.973 14.484,8.965L11,6.956ZM11.602,11.045C11.587,11.053 11.577,11.068 11.577,11.085V15.763C11.577,15.798 11.616,15.82 11.647,15.803L15.134,13.781C15.148,13.772 15.157,13.757 15.157,13.741V9.232C15.157,9.197 15.12,9.175 15.089,9.191L11.602,11.045Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/ic_energy_web_22.xml
Normal file
9
core/ui/src/main/res/drawable/ic_energy_web_22.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<path
|
||||
android:pathData="M10.426,16.82C9.756,17.299 8.955,17.56 8.131,17.568C6.707,17.566 5.405,16.793 4.418,15.369C3.531,14.007 3.04,12.425 3,10.801C3,10.77 3.01,10.74 3.028,10.715C3.046,10.691 3.071,10.672 3.1,10.662L4.071,10.229C4.089,10.22 4.108,10.215 4.128,10.215C4.149,10.214 4.169,10.218 4.187,10.225C4.206,10.233 4.223,10.244 4.237,10.258C4.251,10.273 4.262,10.29 4.269,10.308C4.269,10.328 4.288,10.347 4.288,10.367C4.286,11.982 4.718,13.51 5.489,14.639C6.217,15.708 7.167,16.283 8.156,16.284C8.691,16.286 9.214,16.128 9.659,15.831C9.691,15.814 9.729,15.809 9.764,15.817C9.8,15.824 9.833,15.844 9.856,15.872C10.053,16.129 10.251,16.366 10.467,16.603C10.48,16.639 10.483,16.679 10.476,16.717C10.469,16.755 10.452,16.791 10.426,16.82ZM17.567,15.389C16.596,16.791 15.269,17.579 13.847,17.577C12.425,17.575 11.12,16.783 10.135,15.378C9.208,14.033 8.697,12.252 8.7,10.369C8.702,8.631 9.713,7.267 10.978,7.269C12.243,7.271 13.251,8.638 13.248,10.376C13.268,11.891 12.905,13.386 12.193,14.724C12.184,14.741 12.172,14.756 12.157,14.769C12.143,14.781 12.125,14.791 12.107,14.796C12.088,14.802 12.069,14.804 12.05,14.801C12.031,14.799 12.012,14.793 11.995,14.783C11.976,14.783 11.976,14.762 11.955,14.743C11.837,14.604 11.718,14.466 11.62,14.327C11.501,14.156 11.394,13.978 11.297,13.793C11.288,13.772 11.283,13.748 11.283,13.724C11.283,13.7 11.288,13.677 11.297,13.655C11.748,12.613 11.979,11.489 11.976,10.354C11.978,9.505 11.543,8.535 10.969,8.534C10.396,8.533 9.96,9.502 9.958,10.351C9.956,11.966 10.388,13.495 11.159,14.623C11.889,15.691 12.837,16.265 13.825,16.267C14.814,16.268 15.765,15.677 16.497,14.632C17.27,13.502 17.708,11.985 17.711,10.363C17.713,8.742 17.282,7.228 16.51,6.096C16.29,5.763 16.024,5.463 15.72,5.205C15.694,5.175 15.678,5.139 15.674,5.1C15.671,5.061 15.68,5.021 15.701,4.988C15.72,4.967 15.741,4.948 15.761,4.948L16.731,4.515C16.758,4.5 16.789,4.496 16.819,4.503C16.849,4.511 16.875,4.529 16.892,4.554C17.139,4.804 17.364,5.075 17.565,5.363C18.492,6.708 19.003,8.488 19,10.372C18.997,12.255 18.498,14.047 17.567,15.389Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
20
core/ui/src/main/res/drawable/img_core_22.xml
Normal file
20
core/ui/src/main/res/drawable/img_core_22.xml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"/>
|
||||
<path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M0,0h22v22h-22z"
|
||||
android:fillColor="#121212"/>
|
||||
<path
|
||||
android:pathData="M11,4.66L5.501,7.83V14.17L11,17.34L16.499,14.17V7.83L11,4.66ZM11.231,3.062C11.088,2.979 10.912,2.979 10.769,3.062L4.231,6.831C4.088,6.914 4,7.066 4,7.231V14.769C4,14.934 4.088,15.086 4.231,15.169L10.769,18.938C10.912,19.021 11.088,19.021 11.231,18.938L17.769,15.169C17.912,15.086 18,14.934 18,14.769V7.231C18,7.066 17.912,6.914 17.769,6.831L11.231,3.062ZM11,6.956L7.493,8.978V13.022L10.977,15.031C10.991,15.039 11,15.054 11,15.071V15.763C11,15.798 10.961,15.821 10.931,15.803L6.973,13.521C6.866,13.46 6.8,13.345 6.8,13.222V8.778C6.8,8.655 6.866,8.541 6.973,8.479L10.827,6.257C10.934,6.195 11.066,6.195 11.173,6.257L15.146,8.539C15.177,8.557 15.177,8.601 15.147,8.619C14.98,8.718 14.872,8.777 14.729,8.856L14.729,8.856L14.728,8.856C14.67,8.888 14.606,8.923 14.53,8.965C14.516,8.973 14.498,8.973 14.484,8.965L11,6.956ZM11.602,11.045C11.587,11.053 11.577,11.068 11.577,11.085V15.763C11.577,15.798 11.616,15.82 11.647,15.802L15.134,13.781C15.148,13.772 15.157,13.757 15.157,13.741V9.232C15.157,9.197 15.12,9.175 15.089,9.191L11.602,11.045Z"
|
||||
android:fillColor="#FF9211"
|
||||
android:fillType="evenOdd"/>
|
||||
</group>
|
||||
</vector>
|
||||
19
core/ui/src/main/res/drawable/img_energy_web_22.xml
Normal file
19
core/ui/src/main/res/drawable/img_energy_web_22.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"/>
|
||||
<path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M0,0h22v22h-22z"
|
||||
android:fillColor="#A466FF"/>
|
||||
<path
|
||||
android:pathData="M10.426,16.82C9.756,17.299 8.955,17.56 8.131,17.568C6.707,17.566 5.405,16.793 4.418,15.369C3.531,14.007 3.04,12.425 3,10.801C3,10.77 3.01,10.74 3.028,10.715C3.046,10.691 3.071,10.672 3.1,10.662L4.071,10.229C4.089,10.22 4.108,10.215 4.128,10.215C4.149,10.214 4.169,10.218 4.187,10.225C4.206,10.233 4.223,10.244 4.237,10.258C4.251,10.273 4.262,10.29 4.269,10.308C4.269,10.328 4.288,10.347 4.288,10.367C4.286,11.982 4.718,13.51 5.489,14.639C6.217,15.708 7.167,16.283 8.156,16.284C8.691,16.286 9.214,16.128 9.659,15.831C9.691,15.814 9.729,15.809 9.764,15.817C9.8,15.824 9.833,15.844 9.856,15.872C10.053,16.129 10.251,16.366 10.467,16.603C10.48,16.639 10.483,16.679 10.476,16.717C10.469,16.755 10.452,16.791 10.426,16.82ZM17.567,15.389C16.596,16.791 15.269,17.579 13.847,17.577C12.425,17.575 11.12,16.783 10.135,15.378C9.208,14.033 8.697,12.252 8.7,10.369C8.702,8.631 9.713,7.267 10.978,7.269C12.243,7.271 13.251,8.638 13.248,10.376C13.268,11.891 12.905,13.386 12.193,14.724C12.184,14.741 12.172,14.756 12.157,14.769C12.143,14.781 12.125,14.791 12.107,14.796C12.088,14.802 12.069,14.804 12.05,14.801C12.031,14.799 12.012,14.793 11.995,14.783C11.976,14.783 11.976,14.762 11.955,14.743C11.837,14.604 11.718,14.466 11.62,14.327C11.501,14.156 11.394,13.978 11.297,13.793C11.288,13.772 11.283,13.748 11.283,13.724C11.283,13.7 11.288,13.677 11.297,13.655C11.748,12.613 11.979,11.489 11.976,10.354C11.978,9.505 11.543,8.535 10.969,8.534C10.396,8.533 9.96,9.502 9.958,10.351C9.956,11.966 10.388,13.495 11.159,14.623C11.889,15.691 12.837,16.265 13.825,16.267C14.814,16.268 15.765,15.677 16.497,14.632C17.27,13.502 17.708,11.985 17.711,10.363C17.713,8.742 17.282,7.228 16.51,6.096C16.29,5.763 16.024,5.463 15.72,5.205C15.694,5.175 15.678,5.139 15.674,5.1C15.671,5.061 15.68,5.021 15.701,4.988C15.72,4.967 15.741,4.948 15.761,4.948L16.731,4.515C16.758,4.5 16.789,4.496 16.819,4.503C16.849,4.511 16.875,4.529 16.892,4.554C17.139,4.804 17.364,5.075 17.565,5.363C18.492,6.708 19.003,8.488 19,10.372C18.997,12.255 18.498,14.047 17.567,15.389Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
|
@ -2,11 +2,14 @@ package com.tangem.utils.extensions
|
|||
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Converts `BigDecimal?` to `BigDecimal`
|
||||
*
|
||||
* If `BigDecimal?` is `null`, returns `BigDecimal.ZERO`
|
||||
*/
|
||||
/** Returns [BigDecimal] or [BigDecimal.ZERO] if [this] is null */
|
||||
fun BigDecimal?.orZero(): BigDecimal = this ?: BigDecimal.ZERO
|
||||
|
||||
fun BigDecimal.isZero(): Boolean = this.compareTo(BigDecimal.ZERO) == 0
|
||||
/** Checks if [this] is [BigDecimal] */
|
||||
fun BigDecimal.isZero(): Boolean = this.compareTo(BigDecimal.ZERO) == 0
|
||||
|
||||
/** Checks if [this] is positive */
|
||||
fun BigDecimal.isPositive(): Boolean = this.signum() == 1
|
||||
|
||||
/** Removes trailing zeros and returns plain [String] */
|
||||
fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString()
|
||||
Loading…
Add table
Add a link
Reference in a new issue