Updated on 2026-08-14

This commit is contained in:
Tangem 2023-12-04 16:59:35 +03:00
commit 28dd79443d
33 changed files with 245 additions and 54 deletions

View file

@ -29,8 +29,8 @@ class CurrencyConverter(
fun toCrypto(fiat: BigDecimal): BigDecimal {
if (fiat.isZero()) return fiat
val scaledRateValue = rateValue.setScale(decimals, roundingMode)
val scaledFiat = fiat.setScale(decimals, roundingMode)
return scaledFiat.divide(scaledRateValue, RoundingMode.UP)
val fiatValue = fiat.setScale(rateValue.scale(), RoundingMode.UP)
val cryptoValue = fiatValue.divide(rateValue, RoundingMode.UP)
return cryptoValue.setScale(decimals, roundingMode)
}
}

View file

@ -300,9 +300,9 @@ internal sealed class AddCustomTokenWarning(val description: TextReference) {
description = TextReference.Res(R.string.custom_token_validation_error_already_added),
)
/** Unsupported Solana token warning */
object UnsupportedSolanaToken : AddCustomTokenWarning(
description = TextReference.Res(R.string.alert_manage_tokens_unsupported_message),
/** Unsupported token warning */
data class UnsupportedToken(val networkName: String) : AddCustomTokenWarning(
description = TextReference.Res(R.string.alert_manage_tokens_unsupported_message, networkName),
)
object WrongDerivationPath : AddCustomTokenWarning(

View file

@ -18,7 +18,7 @@ internal object AddCustomTokenPreviewData {
return setOf(
AddCustomTokenWarning.PotentialScamToken,
AddCustomTokenWarning.TokenAlreadyAdded,
AddCustomTokenWarning.UnsupportedSolanaToken,
AddCustomTokenWarning.UnsupportedToken(networkName = "Solana"),
)
}

View file

@ -486,8 +486,12 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
return buildSet {
if (!isSupportedToken && !isContractAddressFieldEmpty) add(AddCustomTokenWarning.UnsupportedSolanaToken)
if (isCustomTokenAlreadyAdded()) add(AddCustomTokenWarning.TokenAlreadyAdded)
if (!isSupportedToken && !isContractAddressFieldEmpty) {
add(AddCustomTokenWarning.UnsupportedToken(networkSelectorValue.fullName))
}
if (isCustomTokenAlreadyAdded()) {
add(AddCustomTokenWarning.TokenAlreadyAdded)
}
if (foundToken == null && isAnyTokenFieldsFilled() || foundToken?.isActive == false) {
add(AddCustomTokenWarning.PotentialScamToken)
}

View file

@ -147,7 +147,7 @@ internal object TangemSocialAccounts {
SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"),
SocialNetworkLink(SocialNetwork.Facebook, "https://www.facebook.com/tangemwallet"),
SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"),
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/@tangem3890"),
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/@tangem_official"),
)
val accountsRu: ImmutableList<SocialNetworkLink> = persistentListOf(
SocialNetworkLink(SocialNetwork.Twitter, "https://x.com/tangem"),
@ -158,6 +158,6 @@ internal object TangemSocialAccounts {
SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"),
SocialNetworkLink(SocialNetwork.Facebook, "https://www.facebook.com/tangemwallet"),
SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"),
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/@tangem3890"),
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/@tangem_official"),
)
}

View file

@ -5,7 +5,7 @@ package com.tangem.tap.features.tokens.impl.presentation.models
*/
sealed class SupportTokensState {
object SolanaNetworkUnsupported : SupportTokensState()
object NetworkTokensUnsupported : SupportTokensState()
object UnsupportedCurve : SupportTokensState()
object SupportedToken : SupportTokensState()
}

View file

@ -51,11 +51,12 @@ internal class DefaultTokensListRouter : TokensListRouter {
store.dispatchDialogShow(alert)
}
override fun openSolanaTokensNotSupportAlert() {
override fun openNetworkTokensNotSupportAlert(networkName: String) {
store.dispatchDialogShow(
AppDialog.SimpleOkDialogRes(
headerId = R.string.common_warning,
messageId = R.string.alert_manage_tokens_unsupported_message,
args = listOf(networkName),
),
)
}

View file

@ -37,7 +37,7 @@ internal interface TokensListRouter {
fun openUnsupportedNetworkAlert(blockchain: Blockchain)
/**
* Open alert with Solana tokens error
* Open alert with unsupported networks tokens error
*/
fun openSolanaTokensNotSupportAlert()
fun openNetworkTokensNotSupportAlert(networkName: String)
}

View file

@ -4,7 +4,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.*
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.*
import com.tangem.blockchain.common.Blockchain
import com.tangem.core.analytics.api.AnalyticsEventHandler
@ -37,7 +40,9 @@ import com.tangem.utils.coroutines.Debouncer
import com.tangem.wallet.R
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import timber.log.Timber
@ -406,14 +411,20 @@ internal class TokensListViewModel @Inject constructor(
}
} else {
when (isUnsupportedToken(token.blockchain)) {
SupportTokensState.SolanaNetworkUnsupported -> router.openSolanaTokensNotSupportAlert()
SupportTokensState.NetworkTokensUnsupported -> {
router.openNetworkTokensNotSupportAlert(token.blockchain.fullName)
}
SupportTokensState.SupportedToken -> {
analyticsSender.sendWhenTokenAdded(token.token)
changedTokensList.add(token)
toggledNetwork.changeToggleState()
}
SupportTokensState.UnsupportedCurve -> router.openUnsupportedNetworkAlert(token.blockchain)
null -> Timber.e("Something went wrong in isUnsupportedToken (no scanResponse found)")
SupportTokensState.UnsupportedCurve -> {
router.openUnsupportedNetworkAlert(token.blockchain)
}
null -> {
Timber.e("Something went wrong in isUnsupportedToken (no scanResponse found)")
}
}
}
}
@ -428,7 +439,7 @@ internal class TokensListViewModel @Inject constructor(
// refactor this later by moving all this logic in card config
if (blockchain == Blockchain.Solana && !supportedTokens.contains(Blockchain.Solana)) {
return SupportTokensState.SolanaNetworkUnsupported
return SupportTokensState.NetworkTokensUnsupported
}
val canHandleToken = it.scanResponse.card.canHandleToken(
supportedTokens = supportedTokens,

View file

@ -0,0 +1,13 @@
package com.tangem.tap.network.auth
import com.tangem.datasource.config.ConfigManager
import com.tangem.lib.auth.AuthBearerProvider
internal class DefaultOneInchProvider(
private val configManager: ConfigManager,
) : AuthBearerProvider {
override fun getApiKey(): String {
return configManager.config.oneInchApiKey
}
}

View file

@ -2,10 +2,12 @@ package com.tangem.tap.network.auth.di
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.lib.auth.AuthBearerProvider
import com.tangem.lib.auth.AuthProvider
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.tap.network.auth.DefaultAuthProvider
import com.tangem.tap.network.auth.DefaultExpressAuthProvider
import com.tangem.tap.network.auth.DefaultOneInchProvider
import com.tangem.tap.proxy.AppStateHolder
import dagger.Module
import dagger.Provides
@ -34,4 +36,12 @@ class AuthModule {
configManager = configManager,
)
}
@Provides
@Singleton
fun provideOneInchAuthProvider(configManager: ConfigManager): AuthBearerProvider {
return DefaultOneInchProvider(
configManager = configManager,
)
}
}

View file

@ -107,6 +107,7 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager {
walletConnectProjectId = configValues.walletConnectProjectId,
tangemComAuthorization = configValues.tangemComAuthorization,
tangemExpressApiKey = configValues.tangemExpressApiKey,
oneInchApiKey = configValues.oneInchApiKey,
)
}

View file

@ -20,4 +20,5 @@ data class Config(
val walletConnectProjectId: String = "",
val tangemComAuthorization: String? = null,
val tangemExpressApiKey: String = "",
val oneInchApiKey: String = "",
)

View file

@ -42,6 +42,7 @@ class ConfigValueModel(
val chiaFireAcademyApiKey: String?,
val chiaTangemApiKey: String?,
val tangemExpressApiKey: String,
val oneInchApiKey: String,
)
@JsonClass(generateAdapter = true)

View file

@ -4,7 +4,10 @@ import android.content.Context
import com.squareup.moshi.Moshi
import com.tangem.datasource.api.oneinch.OneInchApi
import com.tangem.datasource.api.oneinch.OneInchApiFactory
import com.tangem.datasource.utils.RequestHeader
import com.tangem.datasource.utils.addHeaders
import com.tangem.datasource.utils.addLoggers
import com.tangem.lib.auth.AuthBearerProvider
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -21,7 +24,11 @@ class OneInchApisModule {
@Provides
@Singleton
fun provideOneInchApiFactory(@NetworkMoshi moshi: Moshi, @ApplicationContext context: Context): OneInchApiFactory {
fun provideOneInchApiFactory(
@NetworkMoshi moshi: Moshi,
@ApplicationContext context: Context,
auth1Inch: AuthBearerProvider,
): OneInchApiFactory {
val networks = mapOf(
ETH_NETWORK to ONE_INCH_ETH_PATH,
BSC_NETWORK to ONE_INCH_BSC_PATH,
@ -38,14 +45,19 @@ class OneInchApisModule {
for ((network, path) in networks) {
apiFactory.putApi(
networkId = network,
api = createOneInchApiWithUrl("$ONE_INCH_BASE_URL$path", moshi, context),
api = createOneInchApiWithUrl("$ONE_INCH_BASE_URL$path", moshi, context, auth1Inch),
)
}
return apiFactory
}
private fun createOneInchApiWithUrl(url: String, moshi: Moshi, context: Context): OneInchApi {
private fun createOneInchApiWithUrl(
url: String,
moshi: Moshi,
context: Context,
auth1Inch: AuthBearerProvider,
): OneInchApi {
return Retrofit.Builder()
.addConverterFactory(
MoshiConverterFactory.create(moshi),
@ -53,6 +65,7 @@ class OneInchApisModule {
.baseUrl(url)
.client(
OkHttpClient.Builder()
.addHeaders(RequestHeader.AuthBearerHeader(auth1Inch))
.addLoggers(context)
.build(),
)
@ -61,7 +74,7 @@ class OneInchApisModule {
}
companion object {
private const val ONE_INCH_BASE_URL = "https://api-tangem.1inch.io/v5.2/"
private const val ONE_INCH_BASE_URL = "https://api.1inch.dev/swap/v5.2/"
private const val ONE_INCH_ETH_PATH = "1/"
private const val ONE_INCH_BSC_PATH = "56/"
private const val ONE_INCH_POLYGON_PATH = "137/"

View file

@ -1,5 +1,6 @@
package com.tangem.datasource.utils
import com.tangem.lib.auth.AuthBearerProvider
import com.tangem.lib.auth.AuthProvider
import com.tangem.lib.auth.ExpressAuthProvider
@ -25,4 +26,8 @@ sealed class RequestHeader(vararg pairs: Pair<String, () -> String>) {
"user-id" to { expressAuthProvider.getUserId() },
"session-id" to { expressAuthProvider.getSessionId() },
)
class AuthBearerHeader(authBearerProvider: AuthBearerProvider) : RequestHeader(
"Authorization" to { "Bearer " + authBearerProvider.getApiKey() },
)
}

View file

@ -94,7 +94,7 @@
<string name="common_fee_selector_option_market">По рынку</string>
<string name="common_fee_selector_option_slow">Медленно</string>
<string name="common_fee_selector_title">Скорость и комиссия</string>
<string name="common_generate_addresses">Сгенерировать адреса</string>
<string name="common_generate_addresses">Получить адреса</string>
<string name="common_import">Импортировать</string>
<string name="common_like">Нравится</string>
<string name="common_locked">Заблокирован</string>
@ -641,10 +641,10 @@
<string name="warning_low_signatures_title">Малое количество подписей</string>
<string name="warning_manage_tokens_legacy_derivation_message">Токены на разных сетях могут иметь разные адреса. Пожалуйста, убедитесь при переводе средств, что ваш адрес соответствует сети.</string>
<plurals name="warning_missing_derivation_message">
<item quantity="one">Используйте вашу карту, чтобы сгенерировать адрес для %d новой сети</item>
<item quantity="few">Используйте вашу карту, чтобы сгенерировать адреса для %d новых сетей</item>
<item quantity="many">Используйте вашу карту, чтобы сгенерировать адреса для %d новых сетей</item>
<item quantity="other">Используйте вашу карту, чтобы сгенерировать адреса для %d новых сетей</item>
<item quantity="one">Используйте вашу карту, чтобы получить адрес для %d сети</item>
<item quantity="few">Используйте вашу карту, чтобы получить адреса для %d сетей</item>
<item quantity="many">Используйте вашу карту, чтобы получить адреса для %d сетей</item>
<item quantity="other">Используйте вашу карту, чтобы получить адреса для %d сетей</item>
</plurals>
<string name="warning_missing_derivation_title">Некоторые адреса отсутствуют</string>
<string name="warning_network_unreachable_message">В данный момент сеть недоступна. Пожалуйста, попробуйте позже.</string>

View file

@ -92,7 +92,7 @@
<string name="common_fee_selector_option_market">Market</string>
<string name="common_fee_selector_option_slow">Slow</string>
<string name="common_fee_selector_title">Speed and fee</string>
<string name="common_generate_addresses">Generate addresses</string>
<string name="common_generate_addresses">Get addresses</string>
<string name="common_import">Import</string>
<string name="common_learn_and_earn">Learn &amp; Earn</string>
<string name="common_like">Like</string>
@ -648,8 +648,8 @@
<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>
<plurals name="warning_missing_derivation_message">
<item quantity="one">Use your card to generate an address for %d new network</item>
<item quantity="other">Use your card to generate an addresses for %d new networks</item>
<item quantity="one">Use your card to get an address for %d network</item>
<item quantity="other">Use your card to get an addresses for %d networks</item>
</plurals>
<string name="warning_missing_derivation_title">Some addresses are missing</string>
<string name="warning_network_unreachable_message">The network is currently unreachable. Please try again later.</string>

View file

@ -45,7 +45,7 @@ fun getActiveIconRes(blockchainId: String): Int {
"octaspace", "octaspace/test" -> R.drawable.img_octaspace_22
"chia", "chia/test" -> R.drawable.img_chia_22
"NEAR", "NEAR/test" -> R.drawable.img_near_22
"decimal", "decimal/testnet" -> R.drawable.img_decimal_22
"decimal", "decimal/test" -> R.drawable.img_decimal_22
else -> R.drawable.ic_alert_24
}
}

View file

@ -1 +1 @@
/buld
/build

View file

@ -9,6 +9,7 @@ import com.tangem.datasource.local.appcurrency.AvailableAppCurrenciesStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObject
import com.tangem.datasource.local.preferences.utils.getSyncOrNull
import com.tangem.datasource.local.preferences.utils.storeObject
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
@ -42,7 +43,9 @@ internal class DefaultAppCurrencyRepository(
}
withContext(dispatchers.io) {
fetchDefaultAppCurrency()
if (appPreferencesStore.getSyncOrNull(PreferencesKeys.SELECTED_APP_CURRENCY_KEY) == null) {
fetchDefaultAppCurrency()
}
}
}
}

View file

@ -10,7 +10,6 @@ import com.tangem.domain.walletmanager.model.CryptoCurrencyTransaction
import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
import timber.log.Timber
import java.math.BigDecimal
import java.util.concurrent.TimeUnit
import com.tangem.blockchain.common.address.Address as SdkAddress
internal class UpdateWalletManagerResultFactory {
@ -125,7 +124,7 @@ internal class UpdateWalletManagerResultFactory {
return TxHistoryItem(
txHash = hash,
timestampInMillis = TimeUnit.SECONDS.toMillis(millis),
timestampInMillis = millis,
isOutgoing = isOutgoing,
destinationType = TxHistoryItem.DestinationType.Single(
TxHistoryItem.AddressType.User(data.destinationAddress),

View file

@ -13,7 +13,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryToTransactionStateConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsPendingTxToTransactionStateConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
@ -29,7 +29,7 @@ internal class TokenDetailsLoadedBalanceConverter(
) : Converter<Either<CurrencyStatusError, CryptoCurrencyStatus>, TokenDetailsState> {
private val txHistoryItemConverter by lazy {
TokenDetailsTxHistoryToTransactionStateConverter(symbol, decimals, clickIntents)
TokenDetailsPendingTxToTransactionStateConverter(symbol, decimals, clickIntents)
}
override fun convert(value: Either<CurrencyStatusError, CryptoCurrencyStatus>): TokenDetailsState {

View file

@ -15,7 +15,9 @@ import com.tangem.utils.toFormattedCurrencyString
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
internal class TokenDetailsTxHistoryToTransactionStateConverter(
// FIXME: Refactoring needed
/** Same as [TokenDetailsTxHistoryTransactionStateConverter] but with other timestamp format */
internal class TokenDetailsPendingTxToTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,

View file

@ -13,6 +13,8 @@ import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
// FIXME: Refactoring needed
/** Same as [TokenDetailsPendingTxToTransactionStateConverter] but with other timestamp format */
internal class TokenDetailsTxHistoryTransactionStateConverter(
private val symbol: String,
private val decimals: Int,

View file

@ -425,17 +425,19 @@ internal class TokenDetailsViewModel @Inject constructor(
}
override fun onTransactionClick(txHash: String) {
val blockchain = Blockchain.fromId(cryptoCurrency.network.id.value)
// TODO: Fix ton tx urls [REDACTED_TASK_KEY]
if (blockchain == Blockchain.TON || blockchain == Blockchain.TONTestnet) {
return
} else {
router.openUrl(
url = getExplorerTransactionUrlUseCase(
txHash = txHash,
networkId = cryptoCurrency.network.id,
),
)
// TODO: Fix tx urls [REDACTED_TASK_KEY]
when (Blockchain.fromId(cryptoCurrency.network.id.value)) {
Blockchain.TON, Blockchain.TONTestnet,
Blockchain.Decimal, Blockchain.DecimalTestnet,
-> return
else -> {
router.openUrl(
url = getExplorerTransactionUrlUseCase(
txHash = txHash,
networkId = cryptoCurrency.network.id,
),
)
}
}
}

View file

@ -32,7 +32,7 @@ internal class WalletLoadingTxHistoryConverter(
private val txHistoryItemConverter by lazy {
val blockchain = currentCardTypeResolverProvider().getBlockchain()
WalletTxHistoryTransactionStateConverter(
WalletPendingTxToTransactionStateConverter(
symbol = blockchain.currency,
decimals = blockchain.decimals(),
clickIntents = clickIntents,

View file

@ -0,0 +1,109 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
// FIXME: Refactoring needed
/** Same as [WalletTxHistoryTransactionStateConverter] but with other timestamp format */
internal class WalletPendingTxToTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
private val clickIntents: WalletClickIntents,
) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState {
return createTransactionStateItem(item = value)
}
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
return TransactionState.Content(
txHash = item.txHash,
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.extractDirection(),
iconRes = item.extractIcon(),
title = item.extractTitle(),
subtitle = item.extractSubtitle(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
)
}
private fun TxHistoryItem.extractIcon(): Int = if (status == TxHistoryItem.TransactionStatus.Failed) {
R.drawable.ic_close_24
} else {
when (type) {
is TxHistoryItem.TransactionType.Approve -> R.drawable.ic_doc_24
is TxHistoryItem.TransactionType.Operation,
is TxHistoryItem.TransactionType.Swap,
is TxHistoryItem.TransactionType.Transfer,
is TxHistoryItem.TransactionType.UnknownOperation,
-> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24
}
}
private fun TxHistoryItem.extractTitle(): TextReference = when (val type = type) {
is TxHistoryItem.TransactionType.Approve -> resourceReference(R.string.common_approval)
is TxHistoryItem.TransactionType.Operation -> stringReference(type.name)
is TxHistoryItem.TransactionType.Swap -> resourceReference(R.string.common_swap)
is TxHistoryItem.TransactionType.Transfer -> resourceReference(R.string.common_transfer)
is TxHistoryItem.TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation)
}
private fun TxHistoryItem.extractSubtitle(): TextReference =
when (val interactionAddress = interactionAddressType) {
is TxHistoryItem.InteractionAddressType.Contract -> resourceReference(
id = R.string.transaction_history_contract_address,
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
is TxHistoryItem.InteractionAddressType.Multiple -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)),
)
is TxHistoryItem.InteractionAddressType.User -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
}
private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) {
TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed
TxHistoryItem.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed
}
private fun Long.toTimeFormat(): String {
return DateTimeFormatters.formatTime(time = DateTime(this, DateTimeZone.getDefault()))
}
private fun TxHistoryItem.extractDirection() =
if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING
private fun TxHistoryItem.getAmount(): String {
val prefix = when (status) {
TxHistoryItem.TransactionStatus.Failed -> ""
else -> if (isOutgoing) "-" else "+"
}
return prefix + amount.toFormattedCurrencyString(currency = symbol, decimals = decimals)
}
}

View file

@ -12,6 +12,8 @@ import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
// FIXME: Refactoring needed
/** Same as [WalletPendingTxToTransactionStateConverter] but with other timestamp format */
internal class WalletTxHistoryTransactionStateConverter(
private val symbol: String,
private val decimals: Int,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Before After
Before After

View file

@ -88,7 +88,7 @@ spr-client = "3.6.2"
# endregion Other libraries
# region Tangem
tangemBlockchainSdk = "develop-401"
tangemBlockchainSdk = "develop-408"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-312"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^

View file

@ -0,0 +1,12 @@
package com.tangem.lib.auth
/**
* Provides auth for tangemTech API
*/
interface AuthBearerProvider {
/**
* Returns api-key
*/
fun getApiKey(): String
}