Updated on 2026-08-14

This commit is contained in:
Tangem 2022-06-14 11:25:57 +03:00
commit c354933d5f
42 changed files with 344 additions and 211 deletions

View file

@ -93,10 +93,10 @@ dependencies {
implementation 'com.google.android.play:core-ktx:1.8.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'com.tangem:blockchain:develop-85'
implementation 'com.tangem:blockchain:develop-88'
// implementation 'com.tangem:blockchain:0.0.1'
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142'
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-142'
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-154'
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-154'
// WebView
implementation "androidx.browser:browser:1.3.0"

View file

@ -2,6 +2,8 @@ package com.tangem.tap.common.compose.extensions
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalView
import com.tangem.tap.common.extensions.hideKeyboard
@Composable
fun LazyListState.OnBottomReached(loadMoreThreshold: Int, loadMore: () -> Unit) {
@ -17,4 +19,11 @@ fun LazyListState.OnBottomReached(loadMoreThreshold: Int, loadMore: () -> Unit)
LaunchedEffect(shouldLoadMore) {
if (shouldLoadMore) loadMore()
}
}
@Composable
fun LazyListState.HideKeyboardOnScroll() {
if (isScrollInProgress) {
LocalView.current.hideKeyboard()
}
}

View file

@ -8,6 +8,7 @@ import com.tangem.wallet.R
@DrawableRes
fun Blockchain.getRoundIconRes(): Int {
return when (this) {
Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> R.drawable.ic_arbitrum_round
Blockchain.Ducatus -> R.drawable.ic_ducatus
Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_bitcoin_round
Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_round
@ -33,6 +34,7 @@ fun Blockchain.getRoundIconRes(): Int {
@DrawableRes
fun Blockchain.getGreyedOutIconRes(): Int {
return when (this) {
Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> R.drawable.ic_arbitrum_no_color
// Blockchain.Ducatus -> R.drawable.ic_ducatus
Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_bitcoin_no_color
Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_no_color

View file

@ -187,7 +187,7 @@ fun Context.safeStartActivity(
}
fun View.getString(resId: Int, vararg formatArgs: Any?): String {
return context.getString(resId, formatArgs)
return context.getString(resId, *formatArgs)
}
fun View.animateVisibility(

View file

@ -1,6 +1,7 @@
package com.tangem.tap.domain.extensions
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Blockchain.Arbitrum
import com.tangem.tap.features.wallet.redux.Currency
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
import com.tangem.tap.network.exchangeServices.CurrencyExchangeStatus
@ -19,6 +20,7 @@ fun CurrencyExchangeManager.sellIsAllowed(currency: Currency): Boolean {
fun CurrencyExchangeStatus.buyIsAllowed(currency: Currency): Boolean {
if (store.state.globalState.configManager?.config?.isTopUpEnabled == false) return false
if (currency.blockchain == Arbitrum) return false
if (!isBuyAllowed) return false
//TODO: temporary, for the 3.32 release, unlock all buy button

View file

@ -21,7 +21,7 @@ class LoadAvailableCoinsService(
if (isTestNet) {
return Result.Success(
LoadedCoins(
currencies = currenciesRepository.getTestnetCoins(),
currencies = currenciesRepository.getTestnetCoins().filter(searchInput),
moreAvailable = false,
)
)
@ -59,6 +59,15 @@ class LoadAvailableCoinsService(
)
}
private fun List<Currency>.filter(searchInput: String?): List<Currency> {
if (searchInput.isNullOrBlank()) return this
return filter{
it.symbol.contains(searchInput, ignoreCase = true) ||
it.name.contains(searchInput, ignoreCase = true)
}
}
companion object {
const val LOAD_PER_PAGE = 100
}

View file

@ -63,11 +63,17 @@ class WriteProtectedIssuerDataTask(
val counter = (readResponse.issuerDataCounter ?: 0) + 1
val data = twinPublicKey + cardSignature
val signedByIssuer = FileHashHelper.prepareHashes(
cardId, data, counter, issuerKeys.privateKey
cardId = cardId,
fileData = data,
fileCounter = counter,
fileName = null,
privateKey = issuerKeys.privateKey,
)
WriteIssuerDataCommand(
data, signedByIssuer.finalizingSignature!!,
counter, issuerKeys.publicKey
issuerData = data,
issuerDataSignature = signedByIssuer.finalizingSignature!!,
issuerDataCounter = counter,
issuerPublicKey = issuerKeys.publicKey,
).run(session, callback)
}
}

View file

@ -5,6 +5,7 @@ import com.tangem.common.card.Card
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TwinCardNumber
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.tap.domain.termsOfUse.CardTou
import com.tangem.wallet.R
@ -58,4 +59,5 @@ sealed class DetailsAction : Action {
}
}
data class ChangeAppCurrency(val fiatCurrency: FiatCurrency) : DetailsAction()
}

View file

@ -31,6 +31,9 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
is DetailsAction.ManageSecurity -> {
handleSecurityAction(action, detailsState)
}
is DetailsAction.ChangeAppCurrency ->
detailsState.copy(appCurrency = action.fiatCurrency)
else -> detailsState
}
}

View file

@ -4,6 +4,7 @@ import android.net.Uri
import com.tangem.blockchain.common.Wallet
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.entities.Button
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
import com.tangem.tap.store
import org.rekotlin.StateType
@ -19,6 +20,7 @@ data class DetailsState(
val securityScreenState: SecurityScreenState? = null,
val cardTermsOfUseUrl: Uri? = null,
val createBackupAllowed: Boolean = false,
val appCurrency: FiatCurrency = FiatCurrency.Default
) : StateType {
// if you do not delegate - the application crashes on startup,

View file

@ -17,6 +17,7 @@ import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.tap.features.feedback.FeedbackEmail
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentDetailsBinding
@ -114,6 +115,14 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
store.dispatch(DetailsAction.CreateBackup)
}
tvAppCurrency.show(state.scanResponse?.card?.isMultiwalletAllowed != true)
tvAppCurrencyTitle.show(state.scanResponse?.card?.isMultiwalletAllowed != true)
tvAppCurrency.text = state.appCurrency.code
tvAppCurrency.setOnClickListener {
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
}
tvSendFeedback.setOnClickListener {
store.dispatch(GlobalAction.SendFeedback(FeedbackEmail()))
}

View file

@ -128,7 +128,8 @@ class ReceiptReducer : SendInternalReducer {
val totalFiat = amountFiat.plus(feeFiat)
ReceiptTokenFiat(
amountFiat = amountFiat.scaleToFiat(true).stripZeroPlainString(),
feeFiat = feeFiat.scaleToFiat(true).stripZeroPlainString(),
feeFiat = feeFiat.scaleToFiat(true)
.stripZeroPlainString().addPrecisionSign(),
totalFiat = totalFiat.scaleToFiat(true).stripZeroPlainString(),
willSentToken = tokensToSend.stripZeroPlainString(),
willSentFeeCoin = feeCoin.stripZeroPlainString(),

View file

@ -21,6 +21,9 @@ sealed class TokensAction : Action {
object Failure : TokensAction()
}
data class LoadMore(val scanResponse: ScanResponse? = null
) : TokensAction()
data class SetAddedCurrencies(
val wallets: List<WalletData>, val derivationStyle: DerivationStyle?
) : TokensAction()

View file

@ -53,7 +53,13 @@ class TokensMiddleware {
action.searchInput
)
}
is TokensAction.LoadMore -> {
if (store.state.tokensState.needToLoadMore
&& store.state.tokensState.currencies.isNotEmpty()
) {
handleLoadCurrencies(action.scanResponse)
}
}
}
next(action)
}

View file

@ -84,7 +84,11 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens),
}
val onLoadMore = {
store.dispatch(TokensAction.LoadCurrencies(scanResponse = store.state.globalState.scanResponse))
store.dispatch(
TokensAction.LoadMore(
scanResponse = store.state.globalState.scanResponse
)
)
}
cvCurrencies.setContent {

View file

@ -11,6 +11,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.common.compose.extensions.HideKeyboardOnScroll
import com.tangem.tap.common.compose.extensions.OnBottomReached
import com.tangem.tap.domain.tokens.Currency
import com.tangem.tap.features.tokens.redux.ContractAddress
@ -44,6 +45,8 @@ fun ListOfCurrencies(
}
val listState = rememberLazyListState()
listState.HideKeyboardOnScroll()
listState.OnBottomReached(loadMoreThreshold = 40) { onLoadMore() }
LazyColumn(
state = listState,
@ -67,7 +70,6 @@ fun ListOfCurrencies(
)
}
}
listState.OnBottomReached(loadMoreThreshold = 40) { onLoadMore() }
}
val Currency.fullName: String

View file

@ -48,7 +48,7 @@ fun List<PendingTransaction>.filterByCoin(): List<PendingTransaction> {
}
fun List<PendingTransaction>.filterByToken(token: Token): List<PendingTransaction> {
return this.filter { it.currency == token.symbol }
return this.filter { it.transactionData.amount.currencySymbol == token.symbol }
}
fun TransactionData.toPendingTransactionForToken(token: Token, walletAddress: String): PendingTransaction? {

View file

@ -1,16 +1,11 @@
package com.tangem.tap.features.wallet.models
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.features.wallet.redux.ProgressState
import java.math.BigDecimal
data class TotalBalance(
val state: State,
val state: ProgressState,
val fiatAmount: BigDecimal,
val fiatCurrency: FiatCurrency,
) {
enum class State {
Loading,
SomeTokensFailed,
Success,
}
}
)

View file

@ -1,7 +1,11 @@
package com.tangem.tap.features.wallet.redux
import android.content.Context
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.address.AddressType
import com.tangem.common.card.Card
import com.tangem.tap.common.entities.FiatCurrency
@ -11,8 +15,8 @@ import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.wallet.R
import org.rekotlin.Action
import java.math.BigDecimal
import org.rekotlin.Action
sealed class WalletAction : Action {
@ -21,6 +25,7 @@ sealed class WalletAction : Action {
data class SetIfTestnetCard(val isTestnet: Boolean) : WalletAction()
object LoadData : WalletAction() {
object Refresh : WalletAction()
data class Failure(val error: TapError) : WalletAction()
}

View file

@ -1,7 +1,12 @@
package com.tangem.tap.features.wallet.redux
import android.graphics.Bitmap
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.address.AddressType
import com.tangem.common.extensions.isZero
import com.tangem.domain.common.extensions.canHandleToken
@ -19,15 +24,21 @@ import com.tangem.tap.domain.extensions.sellIsAllowed
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
import com.tangem.tap.features.wallet.models.*
import com.tangem.tap.features.wallet.models.PendingTransaction
import com.tangem.tap.features.wallet.models.TotalBalance
import com.tangem.tap.features.wallet.models.WalletRent
import com.tangem.tap.features.wallet.models.WalletWarning
import com.tangem.tap.features.wallet.models.hasPendingTransactions
import com.tangem.tap.features.wallet.models.hasSendableAmounts
import com.tangem.tap.features.wallet.models.isSendableAmount
import com.tangem.tap.features.wallet.redux.reducers.calculateTotalFiatAmount
import com.tangem.tap.features.wallet.redux.reducers.findTotalBalanceState
import com.tangem.tap.features.wallet.redux.reducers.findProgressState
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
import com.tangem.tap.store
import org.rekotlin.StateType
import java.math.BigDecimal
import org.rekotlin.StateType
import kotlin.properties.ReadOnlyProperty
data class WalletState(
@ -55,13 +66,14 @@ data class WalletState(
val isTangemTwins: Boolean
get() = store.state.globalState.scanResponse?.isTangemTwins() == true
val primaryWallet: WalletData? = if (wallets.isNotEmpty()) wallets[0].walletsData[0] else null
val primaryWallet: WalletData? = wallets.firstOrNull()
?.walletsData?.firstOrNull()
val primaryWalletManager: WalletManager? =
if (wallets.isNotEmpty()) wallets[0].walletManager else null
val shouldShowDetails: Boolean =
primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain
primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain
val blockchains: List<Blockchain>
get() = wallets.mapNotNull { it.walletManager?.wallet?.blockchain }
@ -191,6 +203,7 @@ data class WalletState(
fun updateWalletStore(walletStore: WalletStore?): WalletState {
return copy(wallets = replaceWalletInWallets(walletStore))
.updateTotalBalance()
.updateProgressState()
}
private fun updateWalletStores(walletStores: List<WalletStore>): WalletState {
@ -208,6 +221,7 @@ data class WalletState(
}
return copy(wallets = updatedWallets + walletStoresMutable)
.updateTotalBalance()
.updateProgressState()
}
fun removeWallet(walletData: WalletData?): WalletState {
@ -218,6 +232,8 @@ data class WalletState(
&& it.blockchainNetwork.derivationPath == walletData.currency.derivationPath
}
copy(wallets = walletStores)
.updateTotalBalance()
.updateProgressState()
} else {
val walletStore = getWalletStore(walletData.currency)
val walletDataList = walletStore?.walletsData
@ -270,11 +286,13 @@ data class WalletState(
}
private fun updateTotalBalance(): WalletState {
return if (wallets.isNotEmpty()) {
val walletsData = wallets.flatMap(WalletStore::walletsData)
val walletsData = this.wallets
.flatMap(WalletStore::walletsData)
return if (walletsData.isNotEmpty()) {
this.copy(
totalBalance = TotalBalance(
state = walletsData.findTotalBalanceState(),
state = walletsData.findProgressState(),
fiatAmount = walletsData.calculateTotalFiatAmount(),
fiatCurrency = store.state.globalState.appCurrency
)
@ -283,6 +301,20 @@ data class WalletState(
totalBalance = null
)
}
private fun updateProgressState(): WalletState {
val walletsData = this.wallets
.flatMap(WalletStore::walletsData)
return if (walletsData.isNotEmpty()) {
val newProgressState = walletsData.findProgressState()
this.copy(
state = walletsData.findProgressState(),
error = this.error.takeIf { newProgressState == ProgressState.Error }
)
} else this
}
}
sealed interface WalletDialog : StateDialog {
@ -295,7 +327,7 @@ sealed interface WalletDialog : StateDialog {
) : WalletDialog
}
enum class ProgressState : WidgetState { Loading, Done, Error }
enum class ProgressState : WidgetState { Loading, Refreshing, Done, Error }
enum class ErrorType { NoInternetConnection }

View file

@ -7,6 +7,7 @@ import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletDialog
import com.tangem.tap.persistence.FiatCurrenciesPrefStorage
@ -63,6 +64,7 @@ class AppCurrencyMiddleware(
tapWalletManager.rates.clear()
fiatCurrenciesPrefStorage.saveAppCurrency(action.fiatCurrency)
store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency))
store.dispatch(DetailsAction.ChangeAppCurrency(action.fiatCurrency))
store.dispatch(WalletAction.LoadFiatRate())
}

View file

@ -15,7 +15,12 @@ import com.tangem.domain.common.extensions.withMainContext
import com.tangem.operations.attestation.Attestation
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.extensions.copyToClipboard
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.onCardScanned
import com.tangem.tap.common.extensions.shareText
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
@ -29,12 +34,17 @@ import com.tangem.tap.features.wallet.models.PendingTransactionType
import com.tangem.tap.features.wallet.models.filterByCoin
import com.tangem.tap.features.wallet.models.getPendingTransactions
import com.tangem.tap.features.wallet.models.getSendableAmounts
import com.tangem.tap.features.wallet.redux.*
import com.tangem.tap.features.wallet.redux.Currency
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletData
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.WalletStore
import com.tangem.tap.network.NetworkStateChanged
import com.tangem.tap.preferencesStorage
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import java.math.BigDecimal
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch
@ -42,7 +52,6 @@ import org.rekotlin.Action
import org.rekotlin.DispatchFunction
import org.rekotlin.Middleware
import timber.log.Timber
import java.math.BigDecimal
class WalletMiddleware {
private val tradeCryptoMiddleware = TradeCryptoMiddleware()
@ -199,7 +208,8 @@ class WalletMiddleware {
store.dispatchOnMain(WalletAction.Warnings.CheckIfNeeded)
}
}
is WalletAction.LoadData -> {
is WalletAction.LoadData,
is WalletAction.LoadData.Refresh -> {
scope.launch {
val scanNoteResponse = globalState.scanResponse ?: return@launch
if (walletState.walletsData.isNotEmpty()) {

View file

@ -2,7 +2,6 @@ package com.tangem.tap.features.wallet.redux.reducers
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.extensions.isAboveZero
import com.tangem.common.extensions.guard
import com.tangem.tap.common.extensions.toFiatString
import com.tangem.tap.common.extensions.toFormattedCurrencyString
@ -36,8 +35,8 @@ class MultiWalletReducer {
}
val walletData = WalletData(
currencyData = BalanceWidgetData(
BalanceStatus.Loading,
blockchain.blockchain.fullName,
status = BalanceStatus.Loading,
currency = blockchain.blockchain.fullName,
currencySymbol = blockchain.blockchain.currency,
token = cardToken
),
@ -72,8 +71,8 @@ class MultiWalletReducer {
val walletData = WalletData(
currencyData = BalanceWidgetData(
BalanceStatus.Loading,
action.blockchain.blockchain.fullName,
status = BalanceStatus.Loading,
currency = action.blockchain.blockchain.fullName,
currencySymbol = action.blockchain.blockchain.currency,
),
walletAddresses = createAddressList(wallet),
@ -116,7 +115,8 @@ class MultiWalletReducer {
else -> BalanceStatus.VerifiedOnline
}
val tokenWalletData = state.getWalletData(currency)
val isTokenSendButtonEnabled = action.amount.isAboveZero() && pendingTransactions.isEmpty()
val isTokenSendButtonEnabled = tokenWalletData?.shouldEnableTokenSendButton() == true
&& pendingTransactions.isEmpty()
val newTokenWalletData = tokenWalletData?.copy(
currencyData = tokenWalletData.currencyData.copy(
@ -186,7 +186,7 @@ fun Token.toWallet(state: WalletState, blockchain: BlockchainNetwork): WalletDat
return WalletData(
currencyData = BalanceWidgetData(
BalanceStatus.Loading,
status = BalanceStatus.Loading,
currency = this.name,
currencySymbol = this.symbol
),

View file

@ -12,12 +12,7 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.filterByToken
import com.tangem.tap.features.wallet.models.getPendingTransactions
import com.tangem.tap.features.wallet.models.removeUnknownTransactions
import com.tangem.tap.features.wallet.models.toPendingTransactions
import com.tangem.tap.features.wallet.redux.Currency
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.TradeCryptoState
import com.tangem.tap.features.wallet.redux.WalletMainButton
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.*
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.features.wallet.ui.TokenData
@ -61,7 +56,8 @@ class OnWalletLoadedReducer {
val fiatAmount = walletData.fiatRate?.let { coinAmountValue?.toFiatValue(it) }
val newWalletData = walletData.copy(
currencyData = walletData.currencyData.copy(
status = balanceStatus, currency = wallet.blockchain.fullName,
status = balanceStatus,
currency = wallet.blockchain.fullName,
currencySymbol = wallet.blockchain.currency,
blockchainAmount = coinAmountValue,
amount = coinAmountValue,
@ -89,7 +85,7 @@ class OnWalletLoadedReducer {
tokenWalletData?.fiatRate?.let { rate -> tokenAmountValue?.toFiatValue(rate) }
val isTokenSendButtonEnabled = newWalletData.shouldEnableTokenSendButton()
&& tokenPendingTransactions.isEmpty()
&& pendingTransactions.isEmpty()
tokenWalletData?.copy(
currencyData = tokenWalletData.currencyData.copy(
status = tokenBalanceStatus,
@ -110,17 +106,8 @@ class OnWalletLoadedReducer {
val newWallets = tokens + newWalletData
val wallets = walletState.replaceSomeWallets((newWallets))
val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
ProgressState.Loading
} else {
ProgressState.Done
}
return walletState
.updateWalletsData(wallets)
.copy(
state = state,
error = null
)
}
private fun onSingleWalletLoaded(wallet: Wallet, walletState: WalletState): WalletState {

View file

@ -1,48 +1,60 @@
package com.tangem.tap.features.wallet.redux.reducers
import com.tangem.tap.features.wallet.models.TotalBalance
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletData
import com.tangem.tap.features.wallet.ui.BalanceStatus
import java.math.BigDecimal
fun List<WalletData>.findTotalBalanceState(): TotalBalance.State {
return this.mapToTotalBalanceState()
.reduce(TotalBalance.State::or)
fun List<WalletData>.findProgressState(): ProgressState {
return this
.mapToProgressState()
.reduce(ProgressState::or)
}
fun List<WalletData>.calculateTotalFiatAmount(): BigDecimal {
return this.map { it.currencyData.fiatAmount ?: BigDecimal.ZERO }
return this
.map { it.currencyData.fiatAmount ?: BigDecimal.ZERO }
.reduce(BigDecimal::plus)
}
fun List<WalletData>.mapToTotalBalanceState(): List<TotalBalance.State> {
return this.map {
when (it.currencyData.status) {
private fun List<WalletData>.mapToProgressState(): List<ProgressState> {
return this.map { wallet ->
if (wallet.fiatRate == null) ProgressState.Error
else when (wallet.currencyData.status) {
BalanceStatus.Refreshing -> ProgressState.Refreshing
BalanceStatus.VerifiedOnline,
BalanceStatus.SameCurrencyTransactionInProgress,
BalanceStatus.TransactionInProgress -> TotalBalance.State.Success
BalanceStatus.TransactionInProgress,
BalanceStatus.NoAccount -> ProgressState.Done
BalanceStatus.Unreachable,
BalanceStatus.NoAccount,
BalanceStatus.EmptyCard,
BalanceStatus.UnknownBlockchain -> TotalBalance.State.SomeTokensFailed
BalanceStatus.UnknownBlockchain -> ProgressState.Error
BalanceStatus.Loading,
null -> TotalBalance.State.Loading
null -> ProgressState.Loading
}
}
}
infix fun TotalBalance.State.or(newState: TotalBalance.State): TotalBalance.State {
private infix fun ProgressState.or(newState: ProgressState): ProgressState {
return when (this) {
TotalBalance.State.Loading -> when (newState) {
TotalBalance.State.Loading,
TotalBalance.State.SomeTokensFailed,
TotalBalance.State.Success -> this
ProgressState.Loading -> when (newState) {
ProgressState.Loading,
ProgressState.Refreshing,
ProgressState.Error,
ProgressState.Done -> this
}
TotalBalance.State.Success,
TotalBalance.State.SomeTokensFailed -> when (newState) {
TotalBalance.State.Loading,
TotalBalance.State.SomeTokensFailed -> newState
TotalBalance.State.Success -> this
ProgressState.Done,
ProgressState.Error -> when (newState) {
ProgressState.Loading,
ProgressState.Refreshing,
ProgressState.Error -> newState
ProgressState.Done -> this
}
ProgressState.Refreshing -> when (newState) {
ProgressState.Loading -> this
ProgressState.Refreshing,
ProgressState.Error,
ProgressState.Done -> newState
}
}
}

View file

@ -9,6 +9,7 @@ import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.toFiatRateString
import com.tangem.tap.common.extensions.toFiatString
import com.tangem.tap.common.extensions.toFiatValue
import com.tangem.tap.common.extensions.toFormattedCurrencyString
import com.tangem.tap.common.extensions.toFormattedFiatValue
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.TapError
@ -25,7 +26,6 @@ import com.tangem.tap.features.wallet.redux.TradeCryptoState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletAddresses
import com.tangem.tap.features.wallet.redux.WalletData
import com.tangem.tap.features.wallet.redux.WalletDialog
import com.tangem.tap.features.wallet.redux.WalletMainButton
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.WalletStore
@ -135,14 +135,25 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
error = null,
)
}
is WalletAction.LoadData.Refresh -> {
newState = newState.copy(
state = ProgressState.Refreshing,
error = null,
)
}
is WalletAction.LoadWallet -> {
val balanceStatus = if (newState.state == ProgressState.Refreshing) {
BalanceStatus.Refreshing
} else {
BalanceStatus.Loading
}
if (action.blockchain == null) {
val wallets = newState.wallets.map {
it.copy(
walletsData = it.walletsData.map { walletData ->
walletData.copy(
currencyData = walletData.currencyData.copy(
status = BalanceStatus.Loading,
status = balanceStatus,
currency = walletData.currencyData.currency,
currencySymbol = walletData.currencyData.currencySymbol,
),
@ -169,7 +180,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
.map { wallet ->
wallet.copy(
currencyData = wallet.currencyData.copy(
status = BalanceStatus.Loading,
status = balanceStatus,
currency = wallet.currencyData.currency,
currencySymbol = wallet.currencyData.currencySymbol,
),
@ -191,31 +202,37 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
walletState = newState
)
is WalletAction.LoadWallet.NoAccount -> {
val walletData = newState.getWalletData(action.blockchain)?.copy(
currencyData = BalanceWidgetData(
BalanceStatus.NoAccount, action.wallet.blockchain.fullName,
currencySymbol = action.wallet.blockchain.currency,
amountToCreateAccount = action.amountToCreateAccount
val amount = BigDecimal.ZERO
val fiatAmount = BigDecimal.ZERO
val walletData = newState.getWalletData(action.blockchain)?.let { walletData ->
val walletBlockchain = walletData.currency.blockchain
walletData.copy(
currencyData = BalanceWidgetData(
status = BalanceStatus.NoAccount,
currency = action.wallet.blockchain.fullName,
currencySymbol = action.wallet.blockchain.currency,
amount = amount,
amountFormatted = amount.toFormattedCurrencyString(
decimals = walletBlockchain.decimals(),
currency = walletBlockchain.currency,
),
fiatAmount = fiatAmount,
fiatAmountFormatted = fiatAmount.toFiatRateString(
fiatCurrencyName = store.state.globalState.appCurrency.symbol
),
amountToCreateAccount = action.amountToCreateAccount,
)
)
)
}
var updatedWalletStore = newState.getWalletStore(action.blockchain)
?.updateWallets(listOfNotNull(walletData))
val progressState =
if (updatedWalletStore?.walletsData?.any { it.currencyData.status == BalanceStatus.Loading } == true) {
ProgressState.Loading
} else {
ProgressState.Done
}
updatedWalletStore =
updatedWalletStore?.updateWallets(
newState.updateTradeCryptoState(exchangeManager, updatedWalletStore.walletsData)
)
newState = newState.updateWalletStore(updatedWalletStore)
.copy(
state = progressState
)
}
is WalletAction.LoadWallet.Failure -> {
@ -410,19 +427,24 @@ private fun setMultiWalletFiatRate(
state: WalletState
): WalletState {
val newWalletsData = fiatRates.mapNotNull { (currency, rate) ->
val walletStore = state.getWalletStore(currency) ?: return state
val walletStore = state.getWalletStore(currency) ?: return@mapNotNull null
val wallet = walletStore.walletManager?.wallet
val walletData = state.getWalletData(currency) ?: return state
val walletData = state.getWalletData(currency) ?: return@mapNotNull null
val currencyData = walletData.currencyData
val fiatAmount = when (currency) {
var fiatAmount = when (currency) {
is Currency.Blockchain ->
wallet?.amounts?.get(AmountType.Coin)?.value?.toFiatValue(rate)
is Currency.Token ->
wallet?.getTokenAmount(currency.token)?.value?.toFiatValue(rate)
}
if (currencyData.status == BalanceStatus.NoAccount && fiatAmount == null) {
fiatAmount = BigDecimal.ZERO
}
val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(appCurrency.symbol)
state.getWalletData(currency)?.copy(
currencyData = walletData.currencyData.copy(
walletData.copy(
currencyData = currencyData.copy(
fiatAmountFormatted = fiatAmountFormatted,
fiatAmount = fiatAmount
),

View file

@ -13,6 +13,7 @@ enum class BalanceStatus {
SameCurrencyTransactionInProgress,
Unreachable,
Loading,
Refreshing,
NoAccount,
EmptyCard,
UnknownBlockchain

View file

@ -135,15 +135,14 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
showWarningsIfPresent(state.mainWarningsList)
binding.srlWallet.isRefreshing = state.state == ProgressState.Refreshing
binding.srlWallet.setOnRefreshListener {
if (state.state != ProgressState.Loading) {
store.dispatch(WalletAction.LoadData)
if (state.state != ProgressState.Loading ||
state.state != ProgressState.Refreshing
) {
store.dispatch(WalletAction.LoadData.Refresh)
}
}
if (state.state != ProgressState.Loading) {
binding.srlWallet.isRefreshing = false
}
}
private fun showWarningsIfPresent(warnings: List<WarningMessage>) {

View file

@ -64,6 +64,9 @@ class WalletAdapter
fun bind(wallet: WalletData) = with(binding) {
val status = wallet.currencyData.status
// Skip changes when on refreshing status
if (status == BalanceStatus.Refreshing) return@with
val isCustomCurrency = wallet.currency.isCustomCurrency(
derivationStyle = store.state.globalState
.scanResponse
@ -77,14 +80,13 @@ class WalletAdapter
BalanceStatus.Unreachable -> {
root.getString(R.string.wallet_balance_blockchain_unreachable)
}
BalanceStatus.NoAccount -> {
root.getString(R.string.wallet_error_no_account)
}
BalanceStatus.NoAccount,
BalanceStatus.VerifiedOnline,
BalanceStatus.SameCurrencyTransactionInProgress,
BalanceStatus.EmptyCard,
BalanceStatus.UnknownBlockchain,
BalanceStatus.Loading,
BalanceStatus.Refreshing,
null -> null
}
@ -111,11 +113,10 @@ class WalletAdapter
lContent.tvStatus.text = statusMessage
lContent.tvExchangeRate.isVisible = statusMessage == null
lContent.tvExchangeRate.text = if (isCustomCurrency) {
root.getString(id = R.string.token_item_no_rate)
} else {
wallet.fiatRateString
}
lContent.tvExchangeRate.text = wallet.fiatRateString
?: root.getString(id = R.string.token_item_no_rate)
badgeCustomBalance.isVisible = isCustomCurrency
cardWallet.setOnClickListener {
store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet))

View file

@ -2,7 +2,6 @@ package com.tangem.tap.features.wallet.ui.wallet
import android.content.Context
import androidx.appcompat.app.AlertDialog
import com.tangem.tap.common.extensions.dispatchDialogHide
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletDialog
import com.tangem.tap.store
@ -16,27 +15,25 @@ object CurrencySelectionDialog {
val currenciesToShow = dialog.currenciesList
.map { it.displayName }
.toTypedArray()
var currentSelection = dialog.currenciesList
val currentSelection = dialog.currenciesList
.indexOfFirst { it.code == dialog.currentAppCurrency.code }
return AlertDialog.Builder(context)
.setTitle(context.getString(R.string.details_row_title_currency))
.setNegativeButton(context.getString(R.string.common_cancel)) { _, _ -> /* no-op */ }
.setPositiveButton(context.getString(R.string.common_done)) { _, _ ->
dialog.currenciesList.getOrNull(currentSelection)?.let { selectedCurrency ->
.setOnDismissListener {
store.dispatch(WalletAction.DialogAction.Hide)
}
.setSingleChoiceItems(currenciesToShow, currentSelection) { _, which ->
dialog.currenciesList.getOrNull(which)?.let { selectedCurrency ->
store.dispatch(
WalletAction.AppCurrencyAction.SelectAppCurrency(
fiatCurrency = selectedCurrency
)
)
store.dispatch(WalletAction.DialogAction.Hide)
}
}
.setOnDismissListener {
store.dispatchDialogHide()
}
.setSingleChoiceItems(currenciesToShow, currentSelection) { _, which ->
currentSelection = which
}
.create()
}
}

View file

@ -14,6 +14,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.currenciesRepository
import com.tangem.tap.features.tokens.redux.TokensAction
import com.tangem.tap.features.wallet.models.TotalBalance
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.ui.BalanceStatus
@ -125,17 +126,19 @@ class MultiWalletView : WalletView {
) = with(binding.lCardTotalBalance) {
root.isVisible = totalBalance != null
if (totalBalance != null) {
if (totalBalance.state == TotalBalance.State.Loading) {
// Skip changes when on refreshing state
if (totalBalance.state == ProgressState.Refreshing) return@with
if (totalBalance.state == ProgressState.Loading) {
veilBalance.veil()
} else {
veilBalance.unVeil()
}
tvProcessing.animateVisibility(
show = totalBalance.state == TotalBalance.State.SomeTokensFailed
show = totalBalance.state == ProgressState.Error
)
tvBalance.text = if (totalBalance.state == TotalBalance.State.SomeTokensFailed) ""
else totalBalance.fiatAmount.formatAmountAsSpannedString(
tvBalance.text = totalBalance.fiatAmount.formatAmountAsSpannedString(
currencySymbol = totalBalance.fiatCurrency.symbol
)
tvCurrencyName.text = totalBalance.fiatCurrency.code
@ -189,7 +192,6 @@ class MultiWalletView : WalletView {
private fun configureButtonsForEmptyWalletState(binding: FragmentWalletBinding) =
with(binding) {
lButtonsLong.root.show()
lButtonsLong.btnScanLong.setOnClickListener { store.dispatch(WalletAction.Scan) }
lButtonsLong.btnConfirmLong.setOnClickListener { store.dispatch(WalletAction.CreateWallet) }
lButtonsLong.btnConfirmLong.text =
fragment?.getText(R.string.wallet_button_create_wallet)

View file

@ -130,20 +130,8 @@ class SingleWalletView : WalletView {
lButtonsLong.btnConfirmLong
}
val btnScan = if (state.tradeCryptoState.sellingAllowed ||
state.tradeCryptoState.buyingAllowed
) {
lButtonsShort.btnScan
} else {
lButtonsLong.btnScanLong
}
setupConfirmButton(state, btnConfirm, isTwinsWallet)
btnScan.setOnClickListener {
store.dispatch(WalletAction.Scan)
}
lAddress.btnCopy.setOnClickListener {
state.walletAddresses?.selectedAddress?.address?.let { addressString ->
store.dispatch(WalletAction.CopyAddress(addressString, fragment!!.requireContext()))

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:width="12dp"
android:height="12dp" />
<stroke
android:width="2dp"
android:color="@color/white" />
<solid android:color="@color/darkGray1" />
</shape>

View file

@ -52,7 +52,7 @@
app:veilLayout_veiled="true"
app:veilLayout_radius="4dp"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/tv_processing"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:veilLayout_veiled="false">
@ -80,7 +80,8 @@
android:textSize="12sp"
android:text="@string/main_processing_full_amount"
app:layout_constraintTop_toBottomOf="@id/veil_balance"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_currency_name"

View file

@ -216,20 +216,47 @@
android:background="@color/separatorGrey2"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
<TextView
android:id="@+id/tv_app_currency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:drawablePadding="15dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title"
tools:text="USD" />
<TextView
android:id="@+id/tv_app_currency_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_currency"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
<TextView
android:id="@+id/tv_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/disclaimer_title"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/disclaimer_title"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_app_currency_title" />
<TextView
android:id="@+id/tv_card_tou"
@ -279,4 +306,4 @@
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -47,6 +47,15 @@
app:layout_constraintTop_toTopOf="@id/iv_currency"
tools:text="J" />
<View
android:id="@+id/badge_custom_balance"
android:layout_width="12dp"
android:layout_height="12dp"
android:background="@drawable/shape_badge_custom_currency"
android:visibility="gone"
app:layout_constraintTop_toTopOf="@id/iv_currency"
app:layout_constraintEnd_toEndOf="@id/iv_currency" />
<include
layout="@layout/item_currency_wallet_content"
android:id="@+id/l_content"

View file

@ -4,22 +4,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_scan_long"
style="@style/TapBlackButton"
android:layout_width="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:layout_marginBottom="33dp"
android:text="@string/wallet_button_scan"
app:icon="@drawable/ic_scan"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
@ -33,11 +17,10 @@
android:id="@+id/btn_confirm_long"
style="@style/TapButtonWithIcon"
android:layout_width="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="33dp"
android:text="@string/wallet_button_send"
android:layout_marginBottom="8dp"
android:text="@string/wallet_button_send"
app:icon="@drawable/ic_send"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -45,4 +28,4 @@
app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -14,8 +14,8 @@
android:layout_marginBottom="8dp"
android:text="@string/wallet_button_trade"
app:icon="@drawable/ic_arrows_up_down"
app:layout_constraintBottom_toTopOf="@id/btn_scan"
app:layout_constraintEnd_toStartOf="@id/btn_confirm"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btn_confirm"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
@ -34,29 +34,10 @@
android:text="@string/wallet_button_send"
app:icon="@drawable/ic_send"
app:iconGravity="textEnd"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="@id/btn_scan"
app:layout_constraintEnd_toEndOf="parent"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_trade"
app:layout_constraintVertical_bias="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_scan"
style="@style/TapBlackButton"
android:layout_width="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="30dp"
android:layout_marginBottom="33dp"
android:gravity="center"
android:paddingTop="7dp"
android:text="@string/wallet_button_scan"
app:icon="@drawable/ic_scan"
app:iconGravity="textEnd"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -47,7 +47,7 @@
<string name="common_custom">Пользовательский</string>
<string name="main_page_balance">Баланс</string>
<string name="main_processing_full_amount">Обработка полной суммы…</string>
<string name="main_processing_full_amount">В сумме учтены не все монеты</string>
<string name="main_manage_tokens">Управление токенами</string>
<string name="token_item_no_rate">Нет цены</string>
</resources>

View file

@ -47,7 +47,7 @@
<string name="common_custom">Custom</string>
<string name="main_page_balance">Total balance</string>
<string name="main_processing_full_amount">Some networks are unreachable</string>
<string name="main_processing_full_amount">The amount does not include some of your funds</string>
<string name="main_manage_tokens">Manage tokens</string>
<string name="token_item_no_rate">No rate</string>
</resources>

View file

@ -59,10 +59,10 @@ dependencies {
implementation implementation(project(path: ':network'))
implementation implementation(project(path: ':common'))
implementation 'com.tangem:blockchain:develop-85'
implementation 'com.tangem:blockchain:develop-88'
// implementation 'com.tangem:blockchain:0.0.1'
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142'
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-142'
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-154'
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-154'
// Kotlin coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'

View file

@ -75,6 +75,10 @@ object TapWorkarounds {
"AB06" to Blockchain.XRP,
"AB07" to Blockchain.Bitcoin,
"AB08" to Blockchain.Ethereum,
"AB09" to Blockchain.Bitcoin, // new batches for 3.34
"AB10" to Blockchain.Ethereum,
"AB11" to Blockchain.Bitcoin,
"AB12" to Blockchain.Ethereum,
)
private val tangemWalletBatchesWithStandardDerivationType = listOf(