Updated on 2026-08-14

This commit is contained in:
Tangem 2022-09-21 21:19:29 +04:00
commit 392efc7883
33 changed files with 236 additions and 60 deletions

View file

@ -430,6 +430,17 @@
"networkId" : "polkadot/test"
}
]
},
{
"id": "optimistic-ethereum",
"name": "Optimistic Ethereum",
"symbol": "ETH",
"active": true,
"networks": [
{
"networkId": "optimistic-ethereum/test"
}
]
}
],

View file

@ -10,6 +10,7 @@ import com.tangem.Log
import com.tangem.LogFormat
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
import com.tangem.domain.DomainLayer
import com.tangem.domain.common.LogConfig
import com.tangem.network.common.MoshiConverter
import com.tangem.tap.common.AndroidAssetReader
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
@ -38,7 +39,6 @@ val store = Store(
middleware = AppState.getMiddleware(),
state = AppState(),
)
val logConfig = LogConfig()
lateinit var foregroundActivityObserver: ForegroundActivityObserver
@ -69,11 +69,14 @@ class TapApplication : Application(), ImageLoaderFactory {
initConfigManager(configLoader, ::initWithConfigDependency)
initWarningMessagesManager()
BlockchainSdkRetrofitBuilder.enableNetworkLogging = BuildConfig.DEBUG
BlockchainSdkRetrofitBuilder.enableNetworkLogging = LogConfig.network.blockchainSdkNetwork
}
override fun newImageLoader(): ImageLoader {
return createCoilImageLoader(context = this)
return createCoilImageLoader(
context = this,
logEnabled = LogConfig.imageLoader
)
}
private fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) {
@ -131,6 +134,7 @@ class TapApplication : Application(), ImageLoaderFactory {
infoHolder = additionalFeedbackInfo,
logCollector = tangemLogCollector,
preferencesStorage = preferencesStorage,
logEnabled = LogConfig.zendesk,
)
feedbackManager.initChat(
context = context,
@ -142,10 +146,4 @@ class TapApplication : Application(), ImageLoaderFactory {
private fun initWarningMessagesManager() {
store.dispatch(GlobalAction.SetWarningManager(WarningMessagesManager()))
}
}
data class LogConfig(
val coil: Boolean = false,
val storeAction: Boolean = BuildConfig.DEBUG,
val zendesk: Boolean = BuildConfig.DEBUG,
)
}

View file

@ -29,6 +29,8 @@ fun Blockchain.getRoundIconRes(): Int {
Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_round
Blockchain.Gnosis -> R.drawable.ic_gnosis_round
Blockchain.Polkadot, Blockchain.PolkadotTestnet -> R.drawable.ic_polkadot_round
Blockchain.Optimism, Blockchain.OptimismTestnet -> R.drawable.ic_optimism
Blockchain.Dash -> R.drawable.ic_dash
else -> R.drawable.ic_tangem_logo
}
}
@ -57,6 +59,8 @@ fun Blockchain.getGreyedOutIconRes(): Int {
Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_no_color
Blockchain.Gnosis -> R.drawable.ic_gnosis_no_color
Blockchain.Polkadot, Blockchain.PolkadotTestnet -> R.drawable.ic_polkadot_no_color
Blockchain.Optimism, Blockchain.OptimismTestnet -> R.drawable.ic_optimism_no_color
Blockchain.Dash -> R.drawable.ic_dash_no_color
else -> R.drawable.ic_tangem_logo
}
}

View file

@ -1,7 +1,12 @@
package com.tangem.tap.common.extensions
import android.app.Activity
import android.content.*
import android.content.ActivityNotFoundException
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.os.Build
@ -21,7 +26,6 @@ import androidx.fragment.app.Fragment
import com.google.android.material.card.MaterialCardView
import com.tangem.common.extensions.VoidCallback
fun Fragment.getDrawable(@DrawableRes drawableResId: Int): Drawable? {
return ContextCompat.getDrawable(requireContext(), drawableResId)
}
@ -53,6 +57,10 @@ fun View.getString(@StringRes id: Int, vararg formatArgs: String): String {
return context.getString(id, *formatArgs)
}
fun View.getQuantityString(@StringRes id: Int, quantity: Int): String {
return context.resources.getQuantityString(id, quantity, quantity)
}
fun View.getResourceName(): String {
return try {
resources.getResourceEntryName(id)
@ -89,15 +97,13 @@ fun View.invisible(invisible: Boolean = true, invokeBeforeStateChanged: (() -> U
} else {
this.show(invokeBeforeStateChanged)
}
}
fun Context.dpToPixels(dp: Int): Int =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), this.resources.displayMetrics
TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), this.resources.displayMetrics,
).toInt()
fun Context.pixelsToDp(pixels: Int): Int {
return (pixels.toFloat() /
(resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT))
@ -107,7 +113,6 @@ fun Context.pixelsToDp(pixels: Int): Int {
fun Context.dpToPixels(dp: Float): Float =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, this.resources.displayMetrics)
fun Context.pixelsToDp(pixels: Float): Float =
(pixels / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT))
@ -118,14 +123,14 @@ fun MaterialCardView.setMargins(
marginLeftDp: Int = 16,
marginTopDp: Int = 8,
marginRightDp: Int = 16,
marginBottomDp: Int = 8
marginBottomDp: Int = 8,
) {
val params = this.layoutParams
(params as ViewGroup.MarginLayoutParams).setMargins(
context.dpToPixels(marginLeftDp),
context.dpToPixels(marginTopDp),
context.dpToPixels(marginRightDp),
context.dpToPixels(marginBottomDp)
context.dpToPixels(marginBottomDp),
)
this.layoutParams = params
}
@ -144,7 +149,8 @@ fun Activity.setSystemBarTextColor(setTextDark: Boolean) {
}
fun View.hideKeyboard() {
val inputMethodManager = context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? InputMethodManager
val inputMethodManager =
context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? InputMethodManager
inputMethodManager?.hideSoftInputFromWindow(this.windowToken, 0)
}
@ -182,7 +188,7 @@ fun Context.safeStartActivity(
intent: Intent,
options: Bundle? = null,
fallback: ((ActivityNotFoundException) -> Unit)? = null,
finally: VoidCallback? = null
finally: VoidCallback? = null,
) {
try {
this.startActivity(intent, options)
@ -200,7 +206,7 @@ fun View.getString(resId: Int, vararg formatArgs: Any?): String {
fun View.animateVisibility(
show: Boolean,
durationMillis: Long = SHORT_ANIMATION_DURATION,
hiddenVisibility: Int = View.GONE
hiddenVisibility: Int = View.GONE,
) {
if (show) {
this.animate()

View file

@ -7,7 +7,6 @@ import com.tangem.tap.common.extensions.sendEmail
import com.tangem.tap.common.log.TangemLogCollector
import com.tangem.tap.common.zendesk.ZendeskConfig
import com.tangem.tap.foregroundActivityObserver
import com.tangem.tap.logConfig
import com.tangem.tap.persistence.PreferencesStorage
import com.tangem.tap.withForegroundActivity
import com.tangem.wallet.R
@ -31,6 +30,7 @@ class FeedbackManager(
val infoHolder: AdditionalFeedbackInfo,
private val logCollector: TangemLogCollector,
private val preferencesStorage: PreferencesStorage,
private val logEnabled: Boolean = false,
) {
fun initChat(
context: Context,
@ -43,7 +43,7 @@ class FeedbackManager(
)
// Zendesk logs
Logger.setLoggable(logConfig.zendesk)
Logger.setLoggable(logEnabled)
}
fun sendEmail(feedbackData: FeedbackData, onFail: ((Exception) -> Unit)? = null) {

View file

@ -4,7 +4,6 @@ import android.content.Context
import android.util.Log
import coil.ImageLoader
import coil.util.Logger
import com.tangem.tap.logConfig
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import timber.log.Timber
@ -12,11 +11,12 @@ import timber.log.Timber
private const val COIL_LOG_TAG = "COIL"
fun createCoilImageLoader(
context: Context
context: Context,
logEnabled: Boolean = false,
): ImageLoader {
return ImageLoader.Builder(context)
.apply {
if (!logConfig.coil) return@apply
if (!logEnabled) return@apply
logger(CoilTimberLogger())
okHttpClient {

View file

@ -1,6 +1,6 @@
package com.tangem.tap.common.redux
import com.tangem.tap.logConfig
import com.tangem.domain.common.LogConfig
import org.rekotlin.Middleware
import timber.log.Timber
@ -10,7 +10,9 @@ import timber.log.Timber
val logMiddleware: Middleware<AppState> = { dispatch, appState ->
{ nextDispatch ->
{ action ->
if (logConfig.storeAction) Timber.d("Dispatch action: $action")
if (LogConfig.storeAction) {
Timber.d("Dispatch action: $action")
}
nextDispatch(action)
}
}

View file

@ -5,6 +5,7 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.ifNotNull
import com.tangem.common.services.Result
import com.tangem.domain.common.LogConfig
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
@ -96,7 +97,8 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
?.setWalletsInfo(action.walletManagers)
}
is GlobalAction.ExchangeManager.Init -> {
val config = appState()?.globalState?.configManager?.config
val appStateSafe = appState() ?: return
val config = appStateSafe.globalState.configManager?.config
ifNotNull(
config?.mercuryoWidgetId,
config?.mercuryoSecret,
@ -108,8 +110,13 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
apiVersion = MercuryoApi.API_VERSION,
mercuryoWidgetId = mercuryoWidgetId,
secret = mercuryoSecret,
logEnabled = LogConfig.network.mercuryoService,
)
val sellService = MoonPayService(
apiKey = moonPayKey,
secretKey = moonPaySecretKey,
logEnabled = LogConfig.network.moonPayService,
)
val sellService = MoonPayService(moonPayKey, moonPaySecretKey)
val cardProvider = { store.state.globalState.scanResponse?.card }
val exchangeManager = CurrencyExchangeManager(

View file

@ -24,7 +24,10 @@ fun CurrenciesWarning() {
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(16.dp)
.background(Color(0xFFF2F2F2), shape = RoundedCornerShape(10.dp))
.background(
color = Color(0xFFF2F2F2),
shape = RoundedCornerShape(10.dp),
),
)
{
val warning = stringResource(id = R.string.alert_manage_tokens_addresses_message)
@ -33,18 +36,18 @@ fun CurrenciesWarning() {
AnnotatedString.Range(
SpanStyle(fontWeight = FontWeight.Bold),
start = 0,
end = end
)
end = end,
),
)
Text(
text = AnnotatedString(text = warning, spanStyles = spanStyles),
textAlign = TextAlign.Center,
textAlign = TextAlign.Start,
color = Color(0xFF848488),
modifier = Modifier.padding(
top = 8.dp,
bottom = 8.dp,
start = 16.dp,
end = 16.dp
end = 16.dp,
),
fontSize = 13.sp,
fontWeight = FontWeight.Normal,

View file

@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
@ -50,7 +51,7 @@ fun CurrencyItemHeader(
Row(
modifier = Modifier
.fillMaxWidth()
.height(62.dp)
.heightIn(min = 62.dp)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
@ -172,8 +173,7 @@ private fun BlockchainNetworkItem(
addedBlockchains: List<Blockchain>,
) {
val added = addedBlockchains.contains(blockchain)
val icon =
if (added) blockchain?.getRoundIconRes() else blockchain?.getGreyedOutIconRes()
val icon = if (added) blockchain?.getRoundIconRes() else blockchain?.getGreyedOutIconRes()
if (icon != null) {
Box(
Modifier

View file

@ -8,6 +8,7 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.tap.common.extensions.animateVisibility
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
import com.tangem.tap.common.extensions.getQuantityString
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.redux.navigation.AppScreen
@ -27,7 +28,9 @@ import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentWalletBinding
class MultiWalletView : WalletView() {
private lateinit var walletsAdapter: WalletAdapter
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
setFragment(fragment, binding)
onViewCreated()
@ -51,8 +54,7 @@ class MultiWalletView : WalletView() {
if (card?.backupStatus is Card.BackupStatus.Active) {
val cardCount = (card.backupStatus as Card.BackupStatus.Active).cardCount + 1
tvTwinCardNumber.show()
tvTwinCardNumber.text =
fragment?.getString(R.string.wallet_twins_chip_format, 1, cardCount)
tvTwinCardNumber.text = tvTwinCardNumber.getQuantityString(R.plurals.card_label_card_count, cardCount)
} else {
tvTwinCardNumber.hide()
}

View file

@ -89,8 +89,7 @@ class SingleWalletView : WalletView() {
TwinCardNumber.First -> 1
TwinCardNumber.Second -> 2
}
tvTwinCardNumber.text =
fragment?.getString(R.string.wallet_twins_chip_format, number, 2)
tvTwinCardNumber.text = fragment?.getString(R.string.wallet_twins_chip_format, number, 2)
}
if (twinCardsState?.cardNumber == null) {
tvTwinCardNumber.hide()

View file

@ -20,10 +20,13 @@ class MercuryoService(
private val apiVersion: String,
private val mercuryoWidgetId: String,
private val secret: String,
private val logEnabled: Boolean,
) : ExchangeService, ExchangeUrlBuilder {
private val api: MercuryoApi = createRetrofitInstance(MercuryoApi.BASE_URL)
.create(MercuryoApi::class.java)
private val api: MercuryoApi = createRetrofitInstance(
baseUrl = MercuryoApi.BASE_URL,
logEnabled = logEnabled,
).create(MercuryoApi::class.java)
private val blockchainsAvailableToBuy = mutableListOf<Blockchain>()
private val tokensAvailableToBy = mutableMapOf<String, MutableList<Blockchain>>()

View file

@ -20,11 +20,14 @@ import javax.crypto.spec.SecretKeySpec
class MoonPayService(
private val apiKey: String,
private val secretKey: String,
private val logEnabled: Boolean,
) : ExchangeService, ExchangeUrlBuilder {
private val api: MoonPayApi by lazy {
createRetrofitInstance(MoonPayApi.MOOONPAY_BASE_URL)
.create(MoonPayApi::class.java)
createRetrofitInstance(
baseUrl = MoonPayApi.MOOONPAY_BASE_URL,
logEnabled = logEnabled,
).create(MoonPayApi::class.java)
}
private var status: MoonPayStatus? = null

View file

@ -23,7 +23,10 @@ class PayIdService {
return performRequest { payIdApi.setPayId(cardId, publicKey, payId, address, network) }
}
private fun provideRetrofit(): Retrofit = createRetrofitInstance("https://tangem.com/")
private fun provideRetrofit(): Retrofit = createRetrofitInstance(
baseUrl = "https://tangem.com/",
logEnabled = false,
)
}

View file

@ -8,10 +8,13 @@ import com.tangem.network.common.createRetrofitInstance
[REDACTED_AUTHOR]
*/
class PayIdVerifyService(
private val baseUrl: String
private val baseUrl: String,
) {
private val api = createRetrofitInstance(baseUrl).create(PayIdVerifyApi::class.java)
private val api = createRetrofitInstance(
baseUrl = baseUrl,
logEnabled = false,
).create(PayIdVerifyApi::class.java)
suspend fun verifyAddress(user: String, network: String): Result<VerifyPayIdResponse> {
return performRequest { api.verifyAddress(user, createNetworkHeader(network)) }

View 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="M0,0h22v22h-22z"/>
<path
android:pathData="M11,21.988C17.069,21.988 21.988,17.069 21.988,11C21.988,4.931 17.069,0.012 11,0.012C4.931,0.012 0.012,4.931 0.012,11C0.012,17.069 4.931,21.988 11,21.988Z"
android:fillColor="#008DE4"/>
<path
android:pathData="M12.97,4.846H7.66L7.22,7.304L12.012,7.311C14.372,7.311 15.07,8.168 15.05,9.588C15.038,10.317 14.724,11.549 14.588,11.948C14.224,13.012 13.477,14.227 10.677,14.223L6.02,14.221L5.578,16.682H10.875C12.743,16.682 13.538,16.464 14.379,16.076C16.246,15.215 17.356,13.373 17.8,10.97C18.462,7.392 17.636,4.846 12.97,4.846Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M5.369,9.53C3.979,9.53 3.779,10.436 3.649,10.984C3.476,11.701 3.42,11.991 3.42,11.991H8.856C10.247,11.991 10.446,11.085 10.576,10.537C10.749,9.819 10.805,9.53 10.805,9.53H5.369Z"
android:fillColor="#ffffff"/>
</group>
</vector>

View 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="M0,0h22v22h-22z"/>
<path
android:pathData="M11,21.988C17.069,21.988 21.988,17.069 21.988,11C21.988,4.931 17.069,0.012 11,0.012C4.931,0.012 0.012,4.931 0.012,11C0.012,17.069 4.931,21.988 11,21.988Z"
android:fillColor="#F1F1F1"/>
<path
android:pathData="M12.97,4.846H7.66L7.22,7.304L12.012,7.311C14.372,7.311 15.07,8.168 15.05,9.588C15.038,10.317 14.724,11.549 14.588,11.948C14.224,13.012 13.477,14.227 10.677,14.223L6.02,14.221L5.578,16.682H10.875C12.743,16.682 13.538,16.464 14.379,16.076C16.246,15.215 17.356,13.373 17.8,10.97C18.462,7.392 17.636,4.846 12.97,4.846"
android:fillColor="#A1A1A4"/>
<path
android:pathData="M5.369,9.53C3.979,9.53 3.779,10.436 3.649,10.984C3.476,11.701 3.42,11.991 3.42,11.991H8.856C10.247,11.991 10.446,11.085 10.576,10.537C10.749,9.819 10.805,9.53 10.805,9.53H5.369Z"
android:fillColor="#A1A1A4"/>
</group>
</vector>

View file

@ -0,0 +1,16 @@
<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="M0,0h22v22h-22z" />
<path
android:fillColor="#FF0420"
android:pathData="M11,22C17.075,22 22,17.075 22,11C22,4.925 17.075,0 11,0C4.925,0 0,4.925 0,11C0,17.075 4.925,22 11,22Z" />
<path
android:fillColor="#ffffff"
android:fillType="evenOdd"
android:pathData="M4.244,14.356C4.814,14.777 5.546,14.987 6.439,14.987C7.52,14.987 8.383,14.735 9.029,14.233C9.674,13.722 10.128,12.953 10.391,11.925C10.548,11.294 10.684,10.645 10.796,9.977C10.834,9.737 10.852,9.538 10.852,9.38C10.852,8.855 10.721,8.404 10.458,8.029C10.196,7.646 9.835,7.361 9.378,7.174C8.92,6.978 8.402,6.881 7.824,6.881C5.7,6.881 4.383,7.913 3.872,9.977C3.692,10.735 3.553,11.384 3.456,11.925C3.418,12.165 3.399,12.367 3.399,12.533C3.399,13.321 3.681,13.929 4.244,14.356ZM7.666,12.994C7.374,13.242 7.017,13.366 6.597,13.366C5.876,13.366 5.516,13.02 5.516,12.33C5.516,12.165 5.531,12.007 5.561,11.857C5.696,11.129 5.831,10.514 5.966,10.011C6.094,9.5 6.304,9.121 6.597,8.874C6.897,8.626 7.257,8.502 7.678,8.502C8.391,8.502 8.747,8.844 8.747,9.526C8.747,9.692 8.732,9.853 8.702,10.011C8.612,10.536 8.481,11.151 8.308,11.857C8.18,12.367 7.967,12.746 7.666,12.994ZM11.178,14.795C11.223,14.848 11.287,14.874 11.369,14.874H12.9C12.975,14.874 13.047,14.848 13.114,14.795C13.182,14.743 13.223,14.675 13.238,14.593L13.756,12.127H15.276C16.259,12.127 17.032,11.921 17.595,11.508C18.166,11.095 18.545,10.457 18.732,9.594C18.777,9.391 18.8,9.196 18.8,9.009C18.8,8.356 18.545,7.857 18.034,7.511C17.531,7.166 16.863,6.993 16.03,6.993H13.035C12.96,6.993 12.889,7.02 12.822,7.072C12.754,7.125 12.713,7.192 12.698,7.275L11.144,14.593C11.129,14.668 11.14,14.735 11.178,14.795ZM16.177,10.315C15.944,10.487 15.67,10.573 15.355,10.573H14.06L14.488,8.558H15.839C16.147,8.558 16.364,8.618 16.492,8.738C16.619,8.851 16.683,9.016 16.683,9.234C16.683,9.331 16.672,9.444 16.649,9.572C16.574,9.894 16.417,10.142 16.177,10.315Z" />
</group>
</vector>

View file

@ -0,0 +1,16 @@
<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="M0,0h22v22h-22z" />
<path
android:fillColor="#F1F1F1"
android:pathData="M11,22C17.075,22 22,17.075 22,11C22,4.925 17.075,0 11,0C4.925,0 0,4.925 0,11C0,17.075 4.925,22 11,22Z" />
<path
android:fillColor="#A1A1A4"
android:fillType="evenOdd"
android:pathData="M4.244,14.356C4.814,14.777 5.546,14.987 6.439,14.987C7.52,14.987 8.383,14.735 9.029,14.233C9.674,13.722 10.128,12.953 10.391,11.925C10.548,11.294 10.684,10.645 10.796,9.977C10.834,9.737 10.852,9.538 10.852,9.38C10.852,8.855 10.721,8.404 10.458,8.029C10.196,7.646 9.835,7.361 9.378,7.174C8.92,6.978 8.402,6.881 7.824,6.881C5.7,6.881 4.383,7.913 3.872,9.977C3.692,10.735 3.553,11.384 3.456,11.925C3.418,12.165 3.399,12.367 3.399,12.533C3.399,13.321 3.681,13.929 4.244,14.356ZM7.666,12.994C7.374,13.242 7.017,13.366 6.597,13.366C5.876,13.366 5.516,13.02 5.516,12.33C5.516,12.165 5.531,12.007 5.561,11.857C5.696,11.129 5.831,10.514 5.966,10.011C6.094,9.5 6.304,9.121 6.597,8.874C6.897,8.626 7.257,8.502 7.678,8.502C8.391,8.502 8.747,8.844 8.747,9.526C8.747,9.692 8.732,9.853 8.702,10.011C8.612,10.536 8.481,11.151 8.308,11.857C8.18,12.367 7.967,12.746 7.666,12.994ZM11.178,14.795C11.223,14.848 11.287,14.874 11.369,14.874H12.9C12.975,14.874 13.047,14.848 13.114,14.795C13.182,14.743 13.223,14.675 13.238,14.593L13.756,12.127H15.276C16.259,12.127 17.032,11.921 17.595,11.508C18.166,11.095 18.545,10.457 18.732,9.594C18.777,9.391 18.8,9.196 18.8,9.009C18.8,8.356 18.545,7.857 18.034,7.511C17.531,7.166 16.863,6.993 16.03,6.993H13.035C12.96,6.993 12.889,7.02 12.822,7.072C12.754,7.125 12.713,7.192 12.698,7.275L11.144,14.593C11.129,14.668 11.14,14.735 11.178,14.795ZM16.177,10.315C15.944,10.487 15.67,10.573 15.355,10.573H14.06L14.488,8.558H15.839C16.147,8.558 16.364,8.618 16.492,8.738C16.619,8.851 16.683,9.016 16.683,9.234C16.683,9.331 16.672,9.444 16.649,9.572C16.574,9.894 16.417,10.142 16.177,10.315Z" />
</group>
</vector>

View file

@ -0,0 +1,6 @@
<resources>
<plurals name="card_label_card_count">
<item quantity="one">%d card</item>
<item quantity="other">%d cards</item>
</plurals>
</resources>

View file

@ -0,0 +1,7 @@
<resources>
<plurals name="card_label_card_count">
<item quantity="one">%d card</item>
<item quantity="many">%d cards</item>
<item quantity="other">%d cards</item>
</plurals>
</resources>

View file

@ -0,0 +1,6 @@
<resources>
<plurals name="card_label_card_count">
<item quantity="one">%d card</item>
<item quantity="other">%d cards</item>
</plurals>
</resources>

View file

@ -314,7 +314,6 @@
<string name="onboarding_title_prepare_origin">Основная карта</string>
<string name="onboarding_button_backup_origin">Сканировать основную карту</string>
<string name="onboarding_button_continue_wallet">Перейти к моему кошельку</string>
<string name="card_label_number_format">Карта %1s из %2s</string>
<string name="send_title_currency_format">Отправка %s</string>
<string name="onboarding_subtitle_scan_backup_card_format">Подготовьте резервную карту с номером %s</string>
<string name="onboarding_subtitle_scan_primary_card_format">Подготовьте основную карту с номером %s</string>

View file

@ -0,0 +1,8 @@
<resources>
<plurals name="card_label_card_count">
<item quantity="one">%d карта</item>
<item quantity="few">%d карты</item>
<item quantity="many">%d карт</item>
<item quantity="other">%d карт</item>
</plurals>
</resources>

View file

@ -0,0 +1,8 @@
<resources>
<plurals name="card_label_card_count">
<item quantity="zero">%d card</item>
<item quantity="one">%d card</item>
<item quantity="two">%d cards</item>
<item quantity="other">%d cards</item>
</plurals>
</resources>

View file

@ -286,7 +286,6 @@
<string name="onboarding_title_prepare_origin" translatable="false">Primary card</string>
<string name="onboarding_button_backup_origin" translatable="false">Scan the primary card</string>
<string name="onboarding_button_continue_wallet" translatable="false">Continue to my wallet</string>
<string name="card_label_number_format" translatable="false">Card %1s of %2s</string>
<string name="send_title_currency_format" translatable="false">Sending %s</string>
<string name="onboarding_subtitle_scan_backup_card_format" translatable="false">Prepare the backup card with number %s</string>
<string name="onboarding_subtitle_scan_primary_card_format" translatable="false">Prepare the primary card with number %s</string>

View file

@ -2,7 +2,7 @@ ext.versions = [
kotlin : '1.6.10',
build_gradle : '7.1.3',
tangem_card_sdk : 'develop-159',
tangem_blockchain_sdk: 'develop-113',
tangem_blockchain_sdk: 'develop-115',
// tangem_blockchain_sdk: '0.0.1',
]

View file

@ -0,0 +1,17 @@
package com.tangem.domain.common
import com.tangem.domain.features.BuildConfig
object LogConfig {
val imageLoader: Boolean = false
val storeAction: Boolean = BuildConfig.DEBUG
val zendesk: Boolean = false
val network: NetworkLogConfig = NetworkLogConfig
}
object NetworkLogConfig {
val mercuryoService: Boolean = false
val moonPayService: Boolean = false
val tangemTechService: Boolean = BuildConfig.DEBUG
val blockchainSdkNetwork: Boolean = BuildConfig.DEBUG
}

View file

@ -41,6 +41,9 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? {
"polkadot" -> Blockchain.Polkadot
"polkadot/test" -> Blockchain.PolkadotTestnet
"kusama" -> Blockchain.Kusama
"optimistic-ethereum" -> Blockchain.Optimism
"optimistic-ethereum/test" -> Blockchain.OptimismTestnet
"dash" -> Blockchain.Dash
else -> null
}
}
@ -86,6 +89,9 @@ fun Blockchain.toNetworkId(): String {
Blockchain.Polkadot -> "polkadot"
Blockchain.PolkadotTestnet -> "polkadot/test"
Blockchain.Kusama -> "kusama"
Blockchain.Optimism -> "optimistic-ethereum"
Blockchain.OptimismTestnet -> "optimistic-ethereum/test"
Blockchain.Dash -> "dash"
Blockchain.SaltPay -> "xdai"//TODO
}
}
@ -114,6 +120,8 @@ fun Blockchain.toCoinId(): String {
Blockchain.Dogecoin -> "dogecoin"
Blockchain.Gnosis -> "xdai"
Blockchain.Kusama -> "kusama"
Blockchain.Optimism, Blockchain.OptimismTestnet -> "ethereum"
Blockchain.Dash -> "dash"
Blockchain.SaltPay -> "xdai" //TODO
Blockchain.Unknown -> "unknown"
}

View file

@ -1,6 +1,7 @@
package com.tangem.domain.redux.global
import com.tangem.domain.DomainDialog
import com.tangem.domain.common.LogConfig
import com.tangem.domain.common.ScanResponse
import com.tangem.network.api.tangemTech.TangemTechService
@ -17,5 +18,5 @@ data class DomainGlobalState(
)
data class NetworkServices(
val tangemTechService: TangemTechService = TangemTechService()
val tangemTechService: TangemTechService = TangemTechService(LogConfig.network.tangemTechService)
)

View file

@ -11,9 +11,12 @@ import kotlinx.coroutines.withContext
/**
[REDACTED_AUTHOR]
*/
class TangemTechService {
class TangemTechService(
private val logIsEnabled: Boolean = false,
) {
private val headerInterceptors = mutableListOf<AddHeaderInterceptor>(
CacheControlHttpInterceptor(cacheMaxAge)
CacheControlHttpInterceptor(cacheMaxAge),
)
private var api: TangemTechApi = createApi()
@ -24,7 +27,7 @@ class TangemTechService {
active: Boolean? = null,
searchText: String? = null,
offset: Int? = null,
limit: Int? = null
limit: Int? = null,
): Result<CoinsResponse> = withContext(Dispatchers.IO) {
performRequest {
api.coins(
@ -33,14 +36,14 @@ class TangemTechService {
active = active,
searchText = searchText,
offset = offset,
limit = limit
limit = limit,
)
}
}
suspend fun rates(
currency: String,
ids: List<String>
ids: List<String>,
): Result<RatesResponse> = withContext(Dispatchers.IO) {
performRequest {
api.rates(currency.lowercase(), ids.joinToString(","))
@ -65,7 +68,7 @@ class TangemTechService {
val retrofit = createRetrofitInstance(
baseUrl = baseUrl,
interceptors = headerInterceptors.toList(),
// logEnabled = true,
logEnabled = logIsEnabled,
)
return retrofit.create(TangemTechApi::class.java)
}

View file

@ -13,7 +13,7 @@ fun createRetrofitInstance(
okHttpBuilder: OkHttpClient.Builder = OkHttpClient.Builder(),
interceptors: List<Interceptor> = emptyList(),
converterFactory: Converter.Factory = MoshiConverter.createFactory(),
logEnabled: Boolean = false
logEnabled: Boolean,
): Retrofit {
okHttpBuilder.apply {
callTimeout(10, TimeUnit.SECONDS)