Updated on 2026-08-14

This commit is contained in:
Tangem 2021-06-10 05:26:16 +00:00
commit 9df5383142
35 changed files with 531 additions and 319 deletions

View file

@ -75,7 +75,7 @@ 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-8'
implementation 'com.tangem:blockchain:develop-11'
implementation 'com.tangem:core:develop-15'
implementation 'com.tangem:sdk:develop-15'

View file

@ -28,9 +28,15 @@ fun Picasso.loadCurrenciesIcon(
textView.text = null
when {
token?.symbol == QCX -> {
this.load(R.drawable.ic_qcx)?.into(imageView)
}
url != null -> {
if (token != null) {
setTokenImage(imageView, textView, token)
}
this.load(url)
.placeholder(R.drawable.shape_circle)
.noPlaceholder()
?.into(imageView,
object : Callback {
override fun onError(e: Exception?) {
@ -38,12 +44,13 @@ fun Picasso.loadCurrenciesIcon(
}
override fun onSuccess() {
if (token != null) {
imageView.colorFilter = null
textView.text = null
}
}
})
}
token?.symbol == QCX -> {
this.load(R.drawable.ic_qcx)?.into(imageView)
}
else -> {
setOfflineCurrencyImage(imageView, textView, token, blockchain)
}

View file

@ -26,12 +26,21 @@ fun BigDecimal.toFormattedCurrencyString(decimals: Int, currency: String): Strin
return "${this.toFormattedString(decimals)} $currency"
}
fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: FiatCurrencyName): String? {
fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: FiatCurrencyName): String {
var fiatValue = rateValue.multiply(this)
fiatValue = fiatValue.setScale(2, RoundingMode.DOWN)
return "≈ ${fiatCurrencyName} $fiatValue"
}
fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal {
val fiatValue = rateValue.multiply(this)
return fiatValue.setScale(2, RoundingMode.DOWN)
}
fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: FiatCurrencyName): String {
return "≈ ${fiatCurrencyName} $this"
}
fun FiatCurrency.toFormattedString(): String = "${this.name} (${this.symbol}) - ${this.sign}"
fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString()

View file

@ -6,7 +6,6 @@ import com.tangem.commands.common.card.CardStatus
import com.tangem.commands.common.network.Result
import com.tangem.tap.common.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.common.redux.global.FiatCurrencyName
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.currenciesRepository
@ -17,12 +16,14 @@ import com.tangem.tap.domain.tokens.CardCurrencies
import com.tangem.tap.domain.twins.TwinsHelper
import com.tangem.tap.domain.twins.isTwinCard
import com.tangem.tap.features.tokens.redux.TokensAction
import com.tangem.tap.features.wallet.redux.Currency
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.network.NetworkConnectivity
import com.tangem.tap.network.coinmarketcap.CoinMarketCapService
import com.tangem.tap.store
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.math.BigDecimal
@ -64,19 +65,23 @@ class TapWalletManager {
}
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, wallet: Wallet) {
val currencyList = wallet.getTokens().map { it.symbol }.toMutableList()
currencyList.add(wallet.blockchain.currency)
loadFiatRate(fiatCurrency, currencyList)
Timber.d(wallet.getTokens().toString())
val currencies = wallet.getTokens()
.map { Currency.Token(it, wallet.blockchain) }
.plus(Currency.Blockchain(wallet.blockchain))
loadFiatRate(fiatCurrency, currencies)
}
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, cryptoCurrencyName: CryptoCurrencyName) {
val currencyList = listOf(cryptoCurrencyName)
loadFiatRate(fiatCurrency, currencyList)
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, currency: Currency) {
val currencies = listOf(currency)
loadFiatRate(fiatCurrency, currencies)
}
private suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, currencyList: List<CryptoCurrencyName>) {
val results = mutableListOf<Pair<CryptoCurrencyName, Result<BigDecimal>?>>()
currencyList.forEach { results.add(it to coinMarketCapService.getRate(it, fiatCurrency)) }
suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, currencies: List<Currency>) {
val results = mutableListOf<Pair<Currency, Result<BigDecimal>?>>()
currencies.forEach {
results.add(it to coinMarketCapService.getRate(it.currencySymbol, fiatCurrency))
}
handleFiatRatesResult(results)
}
@ -144,11 +149,7 @@ class TapWalletManager {
val config = store.state.globalState.configManager?.config ?: return@withContext
val blockchain = data.card.getBlockchain()
val primaryWalletManager = if (blockchain != null) {
walletManagerFactory.makeWalletManagerForApp(data.card, blockchain)
} else {
null
}
val primaryWalletManager = walletManagerFactory.makePrimaryWalletManager(data)
if (blockchain != null && primaryWalletManager != null) {
val primaryToken = data.card.getToken()
@ -199,8 +200,17 @@ class TapWalletManager {
store.dispatch(WalletAction.MultiWallet.FindBlockchainsInUse(card, walletManagerFactory))
store.dispatch(WalletAction.MultiWallet.FindTokensInUse)
} else {
val blockchains = savedCurrencies.blockchains
val walletManagers = walletManagerFactory.makeWalletManagersForApp(card, blockchains)
val blockchains = savedCurrencies.blockchains
val walletManagers = if (
presetTokens.isNotEmpty() &&
primaryWalletManager != null && primaryBlockchain != null
) {
val blockchainsWithoutPrimary = blockchains.filterNot { it == primaryBlockchain }
walletManagerFactory.makeWalletManagersForApp(card, blockchainsWithoutPrimary)
.plus(primaryWalletManager)
} else {
walletManagerFactory.makeWalletManagersForApp(card, blockchains)
}
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManagers))
store.dispatch(WalletAction.MultiWallet.AddBlockchains(blockchains))
@ -259,7 +269,7 @@ class TapWalletManager {
}
}
private suspend fun handleFiatRatesResult(results: List<Pair<CryptoCurrencyName, Result<BigDecimal>?>>) {
private suspend fun handleFiatRatesResult(results: List<Pair<Currency, Result<BigDecimal>?>>) {
withContext(Dispatchers.Main) {
results.map {
when (it.second) {

View file

@ -1,11 +1,8 @@
package com.tangem.tap.domain.configurable.warningMessage
import com.tangem.TangemSdkError
import com.tangem.blockchain.common.Blockchain
import com.tangem.tangem_sdk_new.ui.animation.VoidCallback
import com.tangem.tap.common.extensions.containsAny
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.wallet.R
/**
@ -68,6 +65,10 @@ class WarningMessagesManager(
sortByPriority()
}
fun removeWarnings(messageRes: Int) {
warningsList.removeIf { it.messageResId == messageRes }
}
private fun sortByPriority() {
warningsList.sortBy { it.priority.ordinal }
}

View file

@ -29,14 +29,15 @@ fun Blockchain.minimalAmount(): BigDecimal {
return 1.toBigDecimal().movePointLeft(decimals())
}
fun Blockchain.getCurve(): EllipticCurve? {
fun Blockchain.getSupportedCurves(): List<EllipticCurve>? {
return when (this) {
Blockchain.Unknown -> null
Blockchain.Bitcoin, Blockchain.BitcoinTestnet, Blockchain.BitcoinCash, Blockchain.Litecoin,
Blockchain.Ducatus, Blockchain.Ethereum, Blockchain.EthereumTestnet, Blockchain.RSK,
Blockchain.Tezos, Blockchain.XRP, Blockchain.Binance, Blockchain.BinanceTestnet ->
EllipticCurve.Secp256k1
Blockchain.Cardano, Blockchain.CardanoShelley, Blockchain.Stellar -> EllipticCurve.Ed25519
Blockchain.XRP, Blockchain.Binance, Blockchain.BinanceTestnet -> listOf(EllipticCurve.Secp256k1)
Blockchain.Tezos -> listOf(EllipticCurve.Secp256k1, EllipticCurve.Ed25519)
Blockchain.Cardano, Blockchain.CardanoShelley, Blockchain.Stellar ->
listOf(EllipticCurve.Ed25519)
}
}

View file

@ -44,4 +44,7 @@ fun Card.signedHashesCount(): Int {
}
val Card.remainingSignatures: Int?
get() = this.getSingleWallet()?.remainingSignatures
get() = this.getSingleWallet()?.remainingSignatures
val Card.isWalletDataSupported: Boolean
get() = this.firmwareVersion.major >= 4

View file

@ -5,29 +5,54 @@ import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.commands.common.card.Card
import com.tangem.commands.common.card.EllipticCurve
import com.tangem.commands.wallet.CardWallet
import com.tangem.common.extensions.hexToBytes
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.twins.isTwinCard
fun WalletManagerFactory.makeWalletManagerForApp(card: Card, blockchain: Blockchain): WalletManager? {
val curve = blockchain.getCurve() ?: return null
val publicKey = card.getWallets().firstOrNull { it.curve == curve }?.publicKey ?: return null
return makeWalletManager(card.cardId, publicKey, blockchain, curve)
fun WalletManagerFactory.makeWalletManagerForApp(
card: Card,
blockchain: Blockchain,
): WalletManager? {
val supportedCurves = blockchain.getSupportedCurves() ?: return null
val wallets = card.getWallets().filter { wallet -> supportedCurves.contains(wallet.curve) }
val wallet = selectWallet(wallets)
val publicKey = wallet?.publicKey ?: return null
val curveToUse = wallet.curve ?: return null
return makeWalletManager(card.cardId, publicKey, blockchain, curveToUse)
}
private fun selectWallet(wallets: List<CardWallet>): CardWallet? {
return when (wallets.size) {
0 -> null
1 -> wallets[0]
else -> wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: wallets[0]
}
}
fun WalletManagerFactory.makeWalletManagersForApp(
card: Card, blockchains: List<Blockchain>
card: Card, blockchains: List<Blockchain>,
): List<WalletManager> {
return makeWalletManagersForCurve(card, blockchains, EllipticCurve.Secp256k1) +
makeWalletManagersForCurve(card, blockchains, EllipticCurve.Ed25519)
return blockchains.mapNotNull { blockchain -> makeWalletManagerForApp(card, blockchain) }
}
fun WalletManagerFactory.makeWalletManagersForCurve(
card: Card, blockchains: List<Blockchain>, curve: EllipticCurve
): List<WalletManager> {
val blockchainsForCurve = blockchains.filter { it.getCurve() == curve }
val walletPublicKey = card.getWallets().firstOrNull { it.curve == curve }?.publicKey
return if (walletPublicKey != null) {
makeWalletManagers(card.cardId, walletPublicKey, blockchainsForCurve, curve)
fun WalletManagerFactory.makePrimaryWalletManager(
data: ScanNoteResponse,
): WalletManager? {
val card = data.card
val blockchain = card.getBlockchain()
val supportedCurves = blockchain?.getSupportedCurves() ?: return null
val wallets = card.getWallets().filter { wallet -> supportedCurves.contains(wallet.curve) }
val wallet = selectWallet(wallets)
val publicKey = wallet?.publicKey ?: return null
val curveToUse = wallet.curve ?: return null
return if (card.isTwinCard() && data.secondTwinPublicKey != null) {
makeMultisigWalletManager(
cardId = card.cardId,
walletPublicKey = publicKey, pairPublicKey = data.secondTwinPublicKey.hexToBytes(),
blockchain = blockchain, curve = curveToUse
)
} else {
emptyList()
makeWalletManager(card.cardId, publicKey, blockchain, curveToUse)
}
}

View file

@ -35,6 +35,4 @@ class CreateWalletAndRescanTask : CardSessionRunnable<Card>, PreflightReadCapabl
}
}
}
}

View file

@ -44,7 +44,7 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
val card = this.card?.copy(
isPin1Default = result.data.isPin1Default,
isPin2Default = result.data.isPin2Default
) ?: result.data
)?.also { it.setWallets(card.getWallets()) } ?: result.data
val error = getErrorIfExcludedCard(card)
if (error != null) {

View file

@ -2,7 +2,6 @@ package com.tangem.tap.domain.twins
import com.tangem.CardSession
import com.tangem.CardSessionRunnable
import com.tangem.commands.common.card.CardStatus
import com.tangem.commands.wallet.CreateWalletResponse
import com.tangem.commands.wallet.PurgeWalletCommand
import com.tangem.common.CompletionResult
@ -14,12 +13,15 @@ import com.tangem.tasks.CreateWalletTask
class CreateFirstTwinWalletTask : CardSessionRunnable<CreateWalletResponse> {
override val requiresPin2 = false
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
override fun run(
session: CardSession,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
) {
if (session.environment.card?.getSingleWallet()?.publicKey != null) {
PurgeWalletCommand(TangemSdkConstants.getDefaultWalletIndex()).run(session) { response ->
when (response) {
is CompletionResult.Success -> {
session.environment.card = session.environment.card?.copy(status = CardStatus.Empty)
session.environment.card = session.environment.card?.changeStatusToEmpty()
CreateWalletTask().run(session) { callback(it) }
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(response.error))

View file

@ -3,7 +3,6 @@ package com.tangem.tap.domain.twins
import com.tangem.CardSession
import com.tangem.CardSessionRunnable
import com.tangem.Message
import com.tangem.commands.common.card.CardStatus
import com.tangem.commands.wallet.CreateWalletResponse
import com.tangem.commands.wallet.PurgeWalletCommand
import com.tangem.common.CompletionResult
@ -26,8 +25,7 @@ class CreateSecondTwinWalletTask(
PurgeWalletCommand(TangemSdkConstants.getDefaultWalletIndex()).run(session) { response ->
when (response) {
is CompletionResult.Success -> {
session.environment.card =
session.environment.card?.copy(status = CardStatus.Empty)
session.environment.card = session.environment.card?.changeStatusToEmpty()
finishTask(session, callback)
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(response.error))
@ -43,8 +41,8 @@ class CreateSecondTwinWalletTask(
CreateWalletTask().run(session) { result ->
when (result) {
is CompletionResult.Success -> {
session.environment.card =
session.environment.card?.copy(status = CardStatus.Loaded)
session.environment.card = session.environment.card?.changeStatusToLoaded()
WriteProtectedIssuerDataTask(
firstPublicKey.hexToBytes(), TwinCardsManager.issuerKeys
).run(session) { writeResult ->

View file

@ -3,27 +3,32 @@ package com.tangem.tap.domain.twins
import com.tangem.CardSession
import com.tangem.CardSessionRunnable
import com.tangem.KeyPair
import com.tangem.commands.read.ReadCommand
import com.tangem.common.CompletionResult
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.ScanNoteTask
import com.tangem.tasks.PreflightReadSettings
import com.tangem.tasks.PreflightReadTask
class FinalizeTwinTask(
private val twinPublicKey: ByteArray, private val issuerKeys: KeyPair
) : CardSessionRunnable<ScanNoteResponse> {
private val twinPublicKey: ByteArray, private val issuerKeys: KeyPair,
) : CardSessionRunnable<ScanNoteResponse> {
override val requiresPin2 = true
override fun run(session: CardSession, callback: (result: CompletionResult<ScanNoteResponse>) -> Unit) {
override fun run(
session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit,
) {
WriteProtectedIssuerDataTask(twinPublicKey, issuerKeys).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
ReadCommand().run(session) { readResult ->
is CompletionResult.Success ->
PreflightReadTask(PreflightReadSettings.FullCardRead).run(session) { readResult ->
when (readResult) {
is CompletionResult.Success -> ScanNoteTask(readResult.data).run(session, callback)
is CompletionResult.Failure -> callback(CompletionResult.Failure(readResult.error))
is CompletionResult.Success ->
ScanNoteTask(readResult.data).run(session, callback)
is CompletionResult.Failure ->
callback(CompletionResult.Failure(readResult.error))
}
}
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}

View file

@ -1,7 +1,9 @@
package com.tangem.tap.domain.twins
import com.tangem.commands.common.card.Card
import com.tangem.commands.common.card.CardStatus
import com.tangem.commands.common.card.masks.Product
import com.tangem.commands.wallet.WalletStatus
import com.tangem.tap.common.extensions.isEven
class TwinsHelper {
@ -53,16 +55,16 @@ class TwinsHelper {
private fun String.calculateLuhn(): Int {
val checksum = this.reversed()
.mapIndexed { index, c ->
val digit = if (c in '0'..'9') c - '0' else c - 'A'
if (!index.isEven()) {
digit
} else {
val newDigit = digit * 2
if (newDigit >= 10) newDigit - 9 else newDigit
}
}.sum()
.rem(10)
.mapIndexed { index, c ->
val digit = if (c in '0'..'9') c - '0' else c - 'A'
if (!index.isEven()) {
digit
} else {
val newDigit = digit * 2
if (newDigit >= 10) newDigit - 9 else newDigit
}
}.sum()
.rem(10)
return (10 - checksum) % 10
}
@ -81,4 +83,16 @@ fun Card.isTwinCard(): Boolean {
fun Card.getTwinCardIdForUser(): String {
return TwinsHelper.getTwinCardIdForUser(this.cardId)
}
fun Card.changeStatusToLoaded(): Card {
val wallets = getWallets().map { it.copy(status = WalletStatus.Loaded) }
return copy(status = CardStatus.Loaded)
.also { it.setWallets(wallets) }
}
fun Card.changeStatusToEmpty(): Card {
val wallets = getWallets().map { it.copy(status = WalletStatus.Empty) }
return copy(status = CardStatus.Empty)
.also { it.setWallets(wallets) }
}

View file

@ -5,6 +5,7 @@ import com.tangem.commands.common.card.Card
import com.tangem.commands.common.card.masks.Settings
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.TapWorkarounds
import com.tangem.tap.domain.extensions.isWalletDataSupported
import com.tangem.tap.domain.extensions.signedHashesCount
import com.tangem.tap.domain.extensions.toSendableAmounts
import com.tangem.tap.domain.twins.TwinsHelper
@ -83,8 +84,10 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: Deta
private fun handleEraseWallet(action: DetailsAction.EraseWallet, state: DetailsState): DetailsState {
return when (action) {
DetailsAction.EraseWallet.Check -> {
val notAllowedByCard = state.card?.settingsMask?.contains(Settings.ProhibitPurgeWallet) == true
|| state.card?.settingsMask?.contains(Settings.IsReusable) == false
val notAllowedByCard =
state.card?.settingsMask?.contains(Settings.ProhibitPurgeWallet) == true
|| state.card?.settingsMask?.contains(Settings.IsReusable) == false
|| state.card?.isWalletDataSupported == true
val notEmpty = state.wallets.any {
!it.recentTransactions.isNullOrEmpty() || it.amounts.toSendableAmounts().isNotEmpty()
}

View file

@ -18,6 +18,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Wallet
import com.tangem.commands.common.card.Card
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.domain.TapWorkarounds
import com.tangem.tap.domain.extensions.signedHashesCount
import com.tangem.tap.store
import timber.log.Timber
@ -34,7 +35,6 @@ import java.util.*
class FeedbackManager(
val infoHolder: AdditionalEmailInfo,
private val logCollector: TangemLogCollector,
private val email: String = "support@tangem.com",
) {
private lateinit var activity: Activity
@ -45,7 +45,15 @@ class FeedbackManager(
fun send(emailData: EmailData) {
val fileLog = if (emailData is ScanFailsEmail) createLogFile() else null
sendTo(email, emailData.subject, emailData.joinTogether(infoHolder), fileLog)
sendTo(
email = getSupportEmail(),
subject = emailData.subject, message = emailData.joinTogether(infoHolder),
fileLog = fileLog
)
}
private fun getSupportEmail(): String {
return if (TapWorkarounds.isStart2Coin) S2C_SUPPORT_EMAIL else DEFAULT_SUPPORT_EMAIL
}
private fun sendTo(email: String, subject: String, message: String, fileLog: File? = null) {
@ -102,6 +110,11 @@ class FeedbackManager(
null
}
}
companion object {
const val DEFAULT_SUPPORT_EMAIL = "support@tangem.com"
const val S2C_SUPPORT_EMAIL = "cardsupport@start2coin.com"
}
}
class TangemLogCollector : TangemSdkLogger {

View file

@ -134,11 +134,11 @@ private fun sendTransaction(
dispatch(NavigationAction.PopBackTo())
scope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain.currency))
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain))
}
delay(10000)
withContext(Dispatchers.Main) {
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain.currency))
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain))
}
}
}

View file

@ -1,6 +1,9 @@
package com.tangem.tap.features.tokens.redux
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.tokens.CardCurrencies
import com.tangem.tap.features.wallet.redux.Currency
import com.tangem.tap.features.wallet.redux.WalletData
import org.rekotlin.Action
class TokensReducer {
@ -18,13 +21,21 @@ private fun internalReduce(action: Action, state: AppState): TokensState {
tokensState.copy(currencies = action.currencies)
}
is TokensAction.SetAddedCurrencies -> {
tokensState.copy(addedCurrencies = action.wallets.mapNotNull { it.currencyData.currencySymbol })
tokensState.copy(addedCurrencies = action.wallets.toCardCurrencies())
}
is TokensAction.LoadCardTokens.Success -> {
tokensState.copy(addedTokens = LinkedHashSet(
action.tokens.map { TokenWithAmount(it, null) }
action.tokens.map { TokenWithAmount(it, null) }
))
}
else -> tokensState
}
}
private fun List<WalletData>.toCardCurrencies(): CardCurrencies {
val tokens = mapNotNull { (it.currency as? Currency.Token)?.token }
val blockchains = mapNotNull { (it.currency as? Currency.Blockchain)?.blockchain }
return CardCurrencies(tokens = tokens, blockchains = blockchains)
}

View file

@ -3,12 +3,13 @@ package com.tangem.tap.features.tokens.redux
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Token
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.domain.tokens.CardCurrencies
import com.tangem.tap.features.tokens.ui.adapters.CurrencyListItem
import org.rekotlin.StateType
data class TokensState(
val addedTokens: LinkedHashSet<TokenWithAmount> = LinkedHashSet(),
val addedCurrencies: List<CryptoCurrencyName> = emptyList(),
val addedCurrencies: CardCurrencies? = null,
val currencies: List<CurrencyListItem> = emptyList(),
) : StateType

View file

@ -12,6 +12,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.domain.tokens.CardCurrencies
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.wallet.R
@ -21,7 +22,7 @@ import java.util.*
class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>(DiffUtilCallback) {
var addedCurrencies: List<CryptoCurrencyName> = emptyList()
var addedCurrencies: CardCurrencies? = null
private var unfilteredList = listOf<CurrencyListItem>()
@ -39,12 +40,18 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
0 -> TitleViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_currency_subtitle, parent, false))
1 -> CurrenciesViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_popular_token, parent, false))
else -> CurrenciesViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_popular_token, parent, false))
0 -> TitleViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_currency_subtitle, parent, false)
)
1 -> CurrenciesViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_popular_token, parent, false)
)
else -> CurrenciesViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_popular_token, parent, false)
)
}
}
@ -59,11 +66,11 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
object DiffUtilCallback : DiffUtil.ItemCallback<CurrencyListItem>() {
override fun areContentsTheSame(
oldItem: CurrencyListItem, newItem: CurrencyListItem
oldItem: CurrencyListItem, newItem: CurrencyListItem
) = oldItem == newItem
override fun areItemsTheSame(
oldItem: CurrencyListItem, newItem: CurrencyListItem
oldItem: CurrencyListItem, newItem: CurrencyListItem
) = oldItem == newItem
}
@ -73,20 +80,23 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
if (!query.isNullOrEmpty()) {
val queryNormalized = query.toString().toLowerCase(Locale.US)
list.addAll(
unfilteredList.filter { element ->
when (element) {
is CurrencyListItem.BlockchainListItem -> {
element.blockchain.currency.toLowerCase(Locale.US).contains(queryNormalized)
|| element.blockchain.fullName.toLowerCase(Locale.US).contains(queryNormalized)
unfilteredList.filter { element ->
when (element) {
is CurrencyListItem.BlockchainListItem -> {
element.blockchain.currency.toLowerCase(Locale.US)
.contains(queryNormalized)
|| element.blockchain.fullName.toLowerCase(Locale.US)
.contains(queryNormalized)
}
is CurrencyListItem.TokenListItem -> {
element.token.name.toLowerCase(Locale.US).contains(queryNormalized)
|| element.token.symbol.toLowerCase(Locale.US).contains(queryNormalized)
}
else -> false
}
})
is CurrencyListItem.TokenListItem -> {
element.token.name.toLowerCase(Locale.US).contains(queryNormalized)
|| element.token.symbol.toLowerCase(Locale.US)
.contains(queryNormalized)
}
else -> false
}
})
} else {
list.addAll(unfilteredList)
}
@ -94,14 +104,14 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
}
class CurrenciesViewHolder(val view: View) :
RecyclerView.ViewHolder(view) {
fun bind(currency: CurrencyListItem, addedCurrencies: List<CryptoCurrencyName>) {
RecyclerView.ViewHolder(view) {
fun bind(currency: CurrencyListItem, addedCurrencies: CardCurrencies?) {
when (currency) {
is CurrencyListItem.BlockchainListItem -> {
val blockchain = currency.blockchain
view.tv_currency_name.text = blockchain.fullName
view.tv_currency_symbol.text = blockchain.currency
val isAdded = addedCurrencies.any { it == blockchain.currency }
val isAdded = addedCurrencies?.blockchains?.contains(blockchain) == true
view.btn_add_token.show(!isAdded)
view.btn_token_added.show(isAdded)
@ -122,7 +132,11 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
view.tv_currency_name.text = token.name
view.tv_currency_symbol.text = token.symbol
val isAdded = addedCurrencies.any { it == token.symbol }
val isAdded = addedCurrencies?.tokens
?.any {
it.symbol == token.symbol && it.contractAddress == token.contractAddress
} == true
view.btn_add_token.show(!isAdded)
view.btn_token_added.show(isAdded)
@ -142,7 +156,7 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
}
class TitleViewHolder(val view: View) :
RecyclerView.ViewHolder(view) {
RecyclerView.ViewHolder(view) {
fun bind(title: CurrencyListItem.TitleListItem) {
view.tv_subtitle.text = view.getString(title.titleResId).toUpperCase(Locale.US)
}

View file

@ -24,7 +24,7 @@ sealed class WalletAction : Action {
}
data class LoadWallet(val allowTopUp: Boolean? = null, val currency: CryptoCurrencyName? = null) : WalletAction() {
data class LoadWallet(val allowTopUp: Boolean? = null, val blockchain: Blockchain? = null) : WalletAction() {
data class Success(val wallet: Wallet) : WalletAction()
data class NoAccount(val wallet: Wallet, val amountToCreateAccount: String) : WalletAction()
data class Failure(val wallet: Wallet, val errorMessage: String? = null) : WalletAction()
@ -45,7 +45,7 @@ sealed class WalletAction : Action {
data class SaveCurrencies(val cardCurrencies: CardCurrencies) : MultiWallet()
object FindTokensInUse : MultiWallet()
data class FindBlockchainsInUse(val card: Card, val factory: WalletManagerFactory) : MultiWallet()
data class TokenLoaded(val amount: Amount) : MultiWallet()
data class TokenLoaded(val amount: Amount, val token: Token) : MultiWallet()
data class SelectWallet(val walletData: WalletData?) : MultiWallet()
data class RemoveWallet(val walletData: WalletData) : MultiWallet()
data class SetPrimaryBlockchain(val blockchain: Blockchain) : MultiWallet()
@ -71,16 +71,16 @@ sealed class WalletAction : Action {
class CheckRemainingSignatures(val remainingSignatures: Int?) : Warnings()
}
data class UpdateWallet(val currency: CryptoCurrencyName? = null) : WalletAction() {
data class UpdateWallet(val blockchain: Blockchain? = null) : WalletAction() {
object ScheduleUpdatingWallet : WalletAction()
data class Success(val wallet: Wallet) : WalletAction()
data class Failure(val errorMessage: String? = null) : WalletAction()
}
data class LoadFiatRate(
val wallet: Wallet? = null, val currency: CryptoCurrencyName? = null
val wallet: Wallet? = null, val currency: Currency? = null
) : WalletAction() {
data class Success(val fiatRate: Pair<CryptoCurrencyName, BigDecimal?>) : WalletAction()
data class Success(val fiatRate: Pair<Currency, BigDecimal?>) : WalletAction()
object Failure : WalletAction()
}

View file

@ -30,13 +30,12 @@ data class WalletState(
val walletManagers: List<WalletManager> = emptyList(),
val isMultiwalletAllowed: Boolean = false,
val cardCurrency: CryptoCurrencyName? = null,
val selectedWallet: CryptoCurrencyName? = null,
val selectedWallet: Currency? = null,
val primaryBlockchain: Blockchain? = null,
val primaryToken: Token? = null
) : StateType {
val primaryWallet = if (wallets.isNotEmpty()) wallets[0] else null
// val primaryWalletManager = if (walletManagers.isNotEmpty()) walletManagers[0] else null
val shouldShowDetails: Boolean =
primaryWallet?.currencyData?.status != com.tangem.tap.features.wallet.ui.BalanceStatus.EmptyCard &&
@ -45,19 +44,14 @@ data class WalletState(
val blockchains: List<Blockchain>
get() = walletManagers.map { it.wallet.blockchain }
fun getWalletManager(currencyName: CryptoCurrencyName?): WalletManager? {
if (currencyName == null) return null
val walletManager = walletManagers.find { it.wallet.blockchain.currency == currencyName }
return walletManager ?: getWalletManagerForToken(currencyName)
}
fun getWalletManagerForToken(currencyName: CryptoCurrencyName?): WalletManager? {
fun getWalletManager(token: Token?): WalletManager? {
if (token == null) return null
val ethereumWalletManager = walletManagers.find { it.wallet.blockchain == Blockchain.Ethereum }
return if (ethereumWalletManager?.presetTokens?.find { it.symbol == currencyName } != null) {
return if (ethereumWalletManager?.presetTokens?.find { it == token } != null) {
ethereumWalletManager
} else {
val primaryWalletManager = walletManagers.find { it.wallet.blockchain == primaryBlockchain }
if (primaryWalletManager?.presetTokens?.find { it.symbol == currencyName } != null) {
if (primaryWalletManager?.presetTokens?.find { it == token } != null) {
primaryWalletManager
} else {
ethereumWalletManager
@ -65,38 +59,69 @@ data class WalletState(
}
}
fun getWalletData(currencyName: CryptoCurrencyName?): WalletData? {
if (currencyName == null) return null
return wallets.find { it.currencyData.currencySymbol == currencyName }
fun getWalletManager(currency: Currency?) : WalletManager? {
if (currency?.blockchain == null) return null
return walletManagers.find { it.wallet.blockchain == currency.blockchain }
}
fun getWalletManager(blockchain: Blockchain) : WalletManager? {
return walletManagers.find { it.wallet.blockchain == blockchain }
}
fun getWalletData(currency: Currency?) : WalletData? {
if (currency == null) return null
return wallets.find { it.currency == currency }
}
fun getWalletData(blockchain: Blockchain?): WalletData? {
if (blockchain == null) return null
return wallets.find { (it.currency as? Currency.Blockchain)?.blockchain == blockchain }
}
fun getWalletData(token: Token?): WalletData? {
if (token == null) return null
return wallets.find { (it.currency as? Currency.Token)?.token == token }
}
fun getSelectedWalletData(): WalletData? {
return wallets.find { it.currencyData.currencySymbol == selectedWallet }
return wallets.find { it.currency == selectedWallet }
}
fun canBeRemoved(walletData: WalletData?): Boolean {
if (walletData == null) return false
if (walletData.blockchain != store.state.walletState.primaryBlockchain
&& (walletData.token == null || walletData.token != store.state.walletState.primaryToken)) {
val walletManager = getWalletManager(walletData.currencyData.currencySymbol)
if (!isPrimaryCurrency(walletData)) {
val walletManager = getWalletManager(walletData.currency)
?: return true
if (walletData.token == null && walletManager.presetTokens.isNotEmpty()) return false
if (walletData.currency is Currency.Blockchain &&
walletManager.presetTokens.isNotEmpty()
) {
return false
}
val wallet = walletManager.wallet
if (walletData.blockchain != null) {
if (walletData.currency is Currency.Blockchain) {
return wallet.recentTransactions.toPendingTransactions(wallet.address).isEmpty() &&
wallet.amounts.toSendableAmounts().isEmpty()
} else if (walletData.token != null) (
} else if (walletData.currency is Currency.Token) (
return wallet.recentTransactions.toPendingTransactionsForToken(
walletData.token, wallet.address).isEmpty()
&& wallet.amounts[AmountType.Token(token = walletData.token)]?.isAboveZero() != true
walletData.currency.token, wallet.address).isEmpty()
&& wallet.amounts[AmountType.Token(token = walletData.currency.token)]
?.isAboveZero() != true
)
}
return false
}
private fun isPrimaryCurrency(walletData: WalletData): Boolean {
return (walletData.currency is Currency.Blockchain &&
walletData.currency.blockchain == store.state.walletState.primaryBlockchain)
|| (walletData.currency is Currency.Token &&
walletData.currency.token == store.state.walletState.primaryToken)
}
fun replaceWalletInWallets(walletData: WalletData?): List<WalletData> {
if (walletData == null) return wallets
return wallets.filter { it.currencyData.currency != walletData.currencyData.currency } + walletData
@ -180,14 +205,32 @@ data class WalletData(
val fiatRateString: String? = null,
val fiatRate: BigDecimal? = null,
val mainButton: WalletMainButton = WalletMainButton.SendButton(false),
val token: Token? = null,
val blockchain: Blockchain? = null,
val currency: Currency? = null
) {
fun shouldShowMultipleAddress(): Boolean {
val listOfAddresses = walletAddresses?.list ?: return false
return (currencyData.currencySymbol == Blockchain.Bitcoin.currency ||
currencyData.currencySymbol == Blockchain.BitcoinTestnet.currency ||
currencyData.currencySymbol == Blockchain.CardanoShelley.currency) &&
return (currency?.blockchain == Blockchain.Bitcoin ||
currency?.blockchain == Blockchain.BitcoinTestnet ||
currency?.blockchain == Blockchain.CardanoShelley) &&
listOfAddresses.size > 1
}
}
sealed interface Currency {
val blockchain: com.tangem.blockchain.common.Blockchain
val currencySymbol: CryptoCurrencyName
data class Token(
val token: com.tangem.blockchain.common.Token,
override val blockchain: com.tangem.blockchain.common.Blockchain
) : Currency {
override val currencySymbol: CryptoCurrencyName = token.symbol
}
data class Blockchain(
override val blockchain: com.tangem.blockchain.common.Blockchain
) : Currency {
override val currencySymbol: CryptoCurrencyName = blockchain.currency
}
}

View file

@ -12,6 +12,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.currenciesRepository
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
import com.tangem.tap.domain.extensions.makeWalletManagersForApp
import com.tangem.tap.features.wallet.redux.Currency
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.scope
@ -52,8 +53,8 @@ class MultiWalletMiddleware {
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(it))
}
}
store.dispatch(WalletAction.LoadFiatRate(currency = action.blockchain.currency))
store.dispatch(WalletAction.LoadWallet(currency = action.blockchain.currency))
store.dispatch(WalletAction.LoadFiatRate(currency = Currency.Blockchain(action.blockchain)))
store.dispatch(WalletAction.LoadWallet(blockchain = action.blockchain))
}
is WalletAction.MultiWallet.SaveCurrencies -> {
val cardId = globalState?.scanNoteResponse?.card?.cardId
@ -61,12 +62,15 @@ class MultiWalletMiddleware {
}
is WalletAction.MultiWallet.RemoveWallet -> {
val cardId = globalState?.scanNoteResponse?.card?.cardId
if (action.walletData.token != null) {
walletState?.getWalletManagerForToken(action.walletData.token.symbol)
?.removeToken(action.walletData.token)
cardId?.let { currenciesRepository.removeToken(it, action.walletData.token) }
} else if (action.walletData.blockchain != null) {
cardId?.let { currenciesRepository.removeBlockchain(it, action.walletData.blockchain) }
when (val currency = action.walletData.currency) {
is Currency.Blockchain -> {
cardId?.let { currenciesRepository.removeBlockchain(it, currency.blockchain) }
}
is Currency.Token -> {
walletState?.getWalletManager(currency.token)
?.removeToken(currency.token)
cardId?.let { currenciesRepository.removeToken(it, currency.token) }
}
}
}
is WalletAction.MultiWallet.FindBlockchainsInUse -> {
@ -83,7 +87,7 @@ class MultiWalletMiddleware {
val wallet = walletManager.wallet
val coinAmount = wallet.amounts[AmountType.Coin]?.value
if (coinAmount != null && !coinAmount.isZero()) {
if (walletState?.getWalletData(wallet.blockchain.currency) == null) {
if (walletState?.getWalletData(wallet.blockchain) == null) {
scope.launch(Dispatchers.Main) {
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(
listOfNotNull(walletManager)))
@ -101,8 +105,12 @@ class MultiWalletMiddleware {
}
}
is WalletAction.MultiWallet.FindTokensInUse -> {
val walletManager = walletState?.getWalletManager(Blockchain.Ethereum.currency)
?: return
val card = globalState?.scanNoteResponse?.card ?: return
val walletManager = walletState?.getWalletManager(Blockchain.Ethereum)
?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(
card = card,
blockchain = Blockchain.Ethereum
)
val tokenFinder = walletManager as TokenFinder
scope.launch {
val result = tokenFinder.findTokens()
@ -110,9 +118,21 @@ class MultiWalletMiddleware {
when (result) {
is Result.Success -> {
if (result.data.isNotEmpty()) {
store.dispatch(WalletAction.MultiWallet.AddTokens(
store.dispatch(
WalletAction.MultiWallet.AddWalletManagers(
walletManager
)
)
store.dispatch(
WalletAction.MultiWallet.AddBlockchain(
walletManager.wallet.blockchain
)
)
store.dispatch(
WalletAction.MultiWallet.AddTokens(
walletManager.presetTokens.toList()
))
)
)
}
}
}
@ -124,20 +144,34 @@ class MultiWalletMiddleware {
private fun addToken(token: Token, walletState: WalletState?, globalState: GlobalState?) {
val card = globalState?.scanNoteResponse?.card ?: return
val walletManager = walletState?.getWalletManager(token.symbol) ?:
globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(
val walletManager = walletState?.getWalletManager(token)
?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(
card = card,
blockchain = Blockchain.Ethereum
)?.also { walletManager ->
)?.also { walletManager ->
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManager))
store.dispatch(WalletAction.MultiWallet.AddBlockchain(walletManager.wallet.blockchain))
}
store.dispatch(
WalletAction.LoadFiatRate(
currency = Currency.Token(
token = token,
blockchain = walletManager?.wallet?.blockchain ?: Blockchain.Ethereum
)
)
)
scope.launch {
val result = walletManager?.addToken(token)
withContext(Dispatchers.Main) {
when (result) {
is Result.Success -> {
store.dispatch(WalletAction.LoadFiatRate(currency = token.symbol))
store.dispatch(WalletAction.MultiWallet.TokenLoaded(result.data))
store.dispatch(
WalletAction.MultiWallet.TokenLoaded(
amount = result.data, token = token
)
)
}
}
}

View file

@ -19,10 +19,7 @@ import com.tangem.tap.domain.twins.TwinsHelper
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.twins.CreateTwinWallet
import com.tangem.tap.features.send.redux.PrepareSendScreen
import com.tangem.tap.features.wallet.redux.ProgressState
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.*
import com.tangem.tap.network.NetworkStateChanged
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -49,12 +46,12 @@ class WalletMiddleware {
is WalletAction.LoadWallet -> {
scope.launch {
if (action.currency == null) {
if (action.blockchain == null) {
walletState?.walletManagers?.map { walletManager ->
globalState?.tapWalletManager?.loadWalletData(walletManager)
}
} else {
val walletManager = walletState?.getWalletManager(action.currency)
val walletManager = walletState?.getWalletManager(action.blockchain)
walletManager?.let { globalState?.tapWalletManager?.loadWalletData(it) }
}
}
@ -62,7 +59,7 @@ class WalletMiddleware {
is WalletAction.LoadWallet.Success -> {
val coinAmount = action.wallet.amounts[AmountType.Coin]?.value
if (coinAmount != null && !coinAmount.isZero()) {
if (walletState?.getWalletData(action.wallet.blockchain.currency) == null) {
if (walletState?.getWalletData(action.wallet.blockchain) == null) {
store.dispatch(WalletAction.MultiWallet.AddBlockchain(action.wallet.blockchain))
store.dispatch(WalletAction.LoadWallet.Success(action.wallet))
}
@ -72,24 +69,24 @@ class WalletMiddleware {
}
is WalletAction.LoadFiatRate -> {
scope.launch {
if (action.wallet != null) {
globalState?.tapWalletManager?.loadFiatRate(
when {
action.wallet != null -> {
globalState?.tapWalletManager?.loadFiatRate(
globalState.appCurrency, action.wallet
)
} else if (action.currency != null) {
globalState?.tapWalletManager?.loadFiatRate(
)
}
action.currency != null -> {
globalState?.tapWalletManager?.loadFiatRate(
globalState.appCurrency, action.currency
)
} else {
walletState?.wallets?.filter { it.blockchain != null }
?.map { walletState.getWalletManager(it.blockchain?.currency) }
?.mapNotNull { walletManager ->
walletManager?.let {
globalState?.tapWalletManager?.loadFiatRate(
globalState.appCurrency, walletManager.wallet
)
}
}
)
}
else -> {
globalState?.tapWalletManager?.loadFiatRate(
fiatCurrency = globalState.appCurrency,
currencies = walletState?.wallets?.mapNotNull { it.currency }
?: emptyList()
)
}
}
}
}
@ -119,9 +116,9 @@ class WalletMiddleware {
}
}
is WalletAction.UpdateWallet -> {
if (action.currency != null) {
if (action.blockchain != null) {
scope.launch {
val walletManager = walletState?.getWalletManager(action.currency)
val walletManager = walletState?.getWalletManager(action.blockchain)
walletManager?.let { globalState?.tapWalletManager?.updateWallet(it) }
}
} else {
@ -195,7 +192,7 @@ class WalletMiddleware {
private fun prepareSendAction(amount: Amount?, state: WalletState?): Action {
val selectedWalletData = state?.getSelectedWalletData()
val currency = selectedWalletData?.currencyData?.currencySymbol
val currency = selectedWalletData?.currency
val walletManager = state?.getWalletManager(currency)
val wallet = walletManager?.wallet
@ -208,12 +205,17 @@ class WalletMiddleware {
} else {
val amounts = wallet?.amounts?.toSendableAmounts()
if (currency != null && state.isMultiwalletAllowed) {
val amountToSend = amounts?.find { it.currencySymbol == currency }
?: return WalletAction.Send.ChooseCurrency(amounts)
if (amountToSend.type is AmountType.Token) {
prepareSendActionForToken(amountToSend, state, selectedWalletData, wallet, walletManager)
} else {
PrepareSendScreen(amountToSend, selectedWalletData.fiatRate, walletManager)
when (currency) {
is Currency.Blockchain -> {
val amountToSend = amounts?.find { it.currencySymbol == currency.blockchain.currency }
?: return WalletAction.Send.ChooseCurrency(amounts)
PrepareSendScreen(amountToSend, selectedWalletData.fiatRate, walletManager)
}
is Currency.Token -> {
val amountToSend = amounts?.find { it.currencySymbol == currency.token.symbol }
?: return WalletAction.Send.ChooseCurrency(amounts)
prepareSendActionForToken(amountToSend, state, selectedWalletData, wallet, walletManager)
}
}
} else {
if (amounts?.size ?: 0 > 1) {
@ -230,7 +232,7 @@ class WalletMiddleware {
amount: Amount, state: WalletState?, selectedWalletData: WalletData?, wallet: Wallet?,
walletManager: WalletManager?
): PrepareSendScreen {
val coinRate = state?.getWalletData(wallet?.blockchain?.currency)?.fiatRate
val coinRate = state?.getWalletData(wallet?.blockchain)?.fiatRate
val tokenRate = if (state?.isMultiwalletAllowed == true) {
selectedWalletData?.fiatRate
} else {

View file

@ -24,6 +24,7 @@ import com.tangem.tap.network.NetworkConnectivity
import com.tangem.tap.preferencesStorage
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -53,6 +54,10 @@ class WarningsMiddleware {
if (action.remainingSignatures != null &&
action.remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING
) {
store.state.globalState.warningManager
?.removeWarnings(
messageRes = R.string.warning_low_signatures_format
)
addWarningMessage(
warning =
WarningMessagesManager.remainingSignaturesNotEnough(action.remainingSignatures),
@ -110,7 +115,7 @@ class WarningsMiddleware {
}
private fun checkIfWarningNeeded(
card: Card
card: Card,
): WarningMessage? {
if (card.isTwinCard()) return null

View file

@ -1,6 +1,7 @@
package com.tangem.tap.features.wallet.redux.reducers
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.isZero
import com.tangem.tap.common.extensions.toFiatString
import com.tangem.tap.common.extensions.toFormattedCurrencyString
@ -18,12 +19,12 @@ class MultiWalletReducer {
return when (action) {
is WalletAction.MultiWallet.AddWalletManagers -> {
state.copy(
walletManagers = state.walletManagers + action.walletManagers
walletManagers = state.walletManagers + action.walletManagers
)
}
is WalletAction.MultiWallet.AddBlockchains -> {
val wallets = action.blockchains.map { blockchain ->
val wallet = state.getWalletManager(blockchain.currency)?.wallet
val wallet = state.getWalletManager(blockchain)?.wallet
val cardToken = if (!state.isMultiwalletAllowed) {
wallet?.getFirstToken()?.symbol?.let { TokenData("", tokenSymbol = it) }
} else {
@ -39,12 +40,12 @@ class MultiWalletReducer {
walletAddresses = createAddressList(wallet),
mainButton = WalletMainButton.SendButton(false),
topUpState = TopUpState(allowed = false),
blockchain = blockchain
currency = Currency.Blockchain(blockchain)
)
}
val selectedWallet = if (!state.isMultiwalletAllowed) {
wallets[0].currencyData.currencySymbol
wallets[0].currency
} else {
state.selectedWallet
}
@ -54,7 +55,7 @@ class MultiWalletReducer {
)
}
is WalletAction.MultiWallet.AddBlockchain -> {
val wallet = state.getWalletManager(action.blockchain.currency)?.wallet
val wallet = state.getWalletManager(action.blockchain)?.wallet
val walletData = WalletData(
currencyData = BalanceWidgetData(
BalanceStatus.Loading,
@ -64,7 +65,7 @@ class MultiWalletReducer {
walletAddresses = createAddressList(wallet),
mainButton = WalletMainButton.SendButton(false),
topUpState = TopUpState(allowed = false),
blockchain = action.blockchain
currency = Currency.Blockchain(action.blockchain)
)
val newState = state.copy(wallets = state.replaceWalletInWallets(walletData))
if (wallet != null && wallet.amounts[AmountType.Coin]?.value != null) {
@ -76,29 +77,29 @@ class MultiWalletReducer {
is WalletAction.MultiWallet.AddTokens -> {
if (!state.isMultiwalletAllowed) return state
val wallets = action.tokens.map { token ->
val walletManager = state.getWalletManager(token)?.wallet
WalletData(
currencyData = BalanceWidgetData(
BalanceStatus.Loading,
currency = token.name,
currencySymbol = token.symbol
),
walletAddresses = createAddressList(
state.getWalletManagerForToken(token.symbol)?.wallet
),
walletAddresses = createAddressList(walletManager),
mainButton = WalletMainButton.SendButton(false),
topUpState = TopUpState(allowed = false),
token = token
currency = Currency.Token(
token = token,
blockchain = walletManager?.blockchain ?: Blockchain.Ethereum
)
)
}
state.copy(wallets = state.replaceSomeWallets(wallets))
}
is WalletAction.MultiWallet.AddToken -> {
if (!state.isMultiwalletAllowed) return state
val walletManager = state.getWalletManager(action.token)?.wallet
val walletAddresses = createAddressList(walletManager)
val walletAddresses = createAddressList(
state.getWalletManagerForToken(action.token.symbol)?.wallet
)
val wallet = WalletData(
currencyData = BalanceWidgetData(
BalanceStatus.Loading,
@ -108,13 +109,16 @@ class MultiWalletReducer {
walletAddresses = walletAddresses,
mainButton = WalletMainButton.SendButton(false),
topUpState = TopUpState(allowed = false),
token = action.token
currency = Currency.Token(
token = action.token,
blockchain = walletManager?.blockchain ?: Blockchain.Ethereum
)
)
val wallets = state.replaceWalletInWallets(wallet)
state.copy(wallets = wallets)
}
is WalletAction.MultiWallet.TokenLoaded -> {
val pendingTransactions = state.getWalletManagerForToken(action.amount.currencySymbol)
val pendingTransactions = state.getWalletManager(action.token)
?.wallet?.let { wallet ->
wallet.recentTransactions.toPendingTransactions(wallet.address)
} ?: emptyList()
@ -127,14 +131,14 @@ class MultiWalletReducer {
pendingTransactions.isNotEmpty() -> BalanceStatus.SameCurrencyTransactionInProgress
else -> BalanceStatus.VerifiedOnline
}
val tokenWalletData = state.getWalletData(action.amount.currencySymbol)
val tokenWalletData = state.getWalletData(action.token)
val newTokenWalletData = tokenWalletData?.copy(
currencyData = tokenWalletData.currencyData.copy(
status = tokenBalanceStatus,
amount = action.amount.value?.toFormattedCurrencyString(
action.amount.decimals, action.amount.currencySymbol
),
fiatAmount = tokenWalletData.fiatRate?.let {
fiatAmountFormatted = tokenWalletData.fiatRate?.let {
action.amount.value
?.toFiatString(it, store.state.globalState.appCurrency)
}
@ -149,12 +153,24 @@ class MultiWalletReducer {
state.copy(isMultiwalletAllowed = action.isMultiwalletAllowed)
is WalletAction.MultiWallet.SelectWallet ->
state.copy(selectedWallet = action.walletData?.currencyData?.currencySymbol)
state.copy(selectedWallet = action.walletData?.currency)
is WalletAction.MultiWallet.RemoveWallet -> {
state.copy(wallets = state.wallets.filterNot {
it.currencyData.currencySymbol == action.walletData.currencyData.currencySymbol
})
val wallets = state.wallets.filterNot {
it.currency == action.walletData.currency
}
if (action.walletData.currency is Currency.Blockchain) {
state.copy(
wallets = wallets,
walletManagers = state.walletManagers.filterNot {
it.wallet.blockchain == action.walletData.currency.blockchain
}
)
} else {
state.copy(wallets = wallets)
}
}
is WalletAction.MultiWallet.SetPrimaryBlockchain ->
state.copy(primaryBlockchain = action.blockchain)

View file

@ -3,9 +3,7 @@ package com.tangem.tap.features.wallet.redux.reducers
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Wallet
import com.tangem.common.extensions.isZero
import com.tangem.tap.common.extensions.toFiatString
import com.tangem.tap.common.extensions.toFormattedCurrencyString
import com.tangem.tap.common.extensions.toFormattedString
import com.tangem.tap.common.extensions.*
import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.features.wallet.models.removeUnknownTransactions
import com.tangem.tap.features.wallet.models.toPendingTransactions
@ -34,7 +32,7 @@ class OnWalletLoadedReducer {
): WalletState {
val fiatCurrencySymbol = store.state.globalState.appCurrency
val amount = wallet.amounts[AmountType.Coin]?.value
if (walletState.getWalletData(wallet.blockchain.currency) == null) {
if (walletState.getWalletData(wallet.blockchain) == null) {
return walletState
}
val formattedAmount = amount?.toFormattedCurrencyString(
@ -50,37 +48,40 @@ class OnWalletLoadedReducer {
} else {
BalanceStatus.VerifiedOnline
}
val walletData = walletState.getWalletData(wallet.blockchain.currency)
val walletData = walletState.getWalletData(wallet.blockchain)
?: WalletData()
val fiatAmount = walletData.fiatRate?.let { amount?.toFiatValue(it) }
val newWalletData = walletData.copy(
currencyData = walletData.currencyData.copy(
status = balanceStatus, currency = wallet.blockchain.fullName,
currencySymbol = wallet.blockchain.currency,
amount = formattedAmount,
fiatAmount = walletData.fiatRate?.let { amount?.toFiatString(it, fiatCurrencySymbol) }
fiatAmount = fiatAmount,
fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(fiatCurrencySymbol)
),
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
mainButton = WalletMainButton.SendButton(sendButtonEnabled)
)
val tokens = wallet.getTokens().mapNotNull { token ->
val tokenWalletData = walletState.getWalletData(token.symbol)
val tokenWalletData = walletState.getWalletData(token)
val tokenPendingTransactions = pendingTransactions.filter { it.currency == token.symbol }
val tokenBalanceStatus = when {
tokenPendingTransactions.isNotEmpty() -> BalanceStatus.TransactionInProgress
pendingTransactions.isNotEmpty() -> BalanceStatus.SameCurrencyTransactionInProgress
else -> BalanceStatus.VerifiedOnline
}
val tokenFiatAmount = tokenWalletData?.fiatRate?.let { rate ->
wallet.getTokenAmount(token)?.value?.toFiatValue(rate)
}
tokenWalletData?.copy(
currencyData = tokenWalletData.currencyData.copy(
status = tokenBalanceStatus,
amount = wallet.getTokenAmount(token)?.value?.toFormattedCurrencyString(
token.decimals, token.symbol
),
fiatAmount = tokenWalletData.fiatRate?.let {
wallet.getTokenAmount(token)?.value
?.toFiatString(it, fiatCurrencySymbol)
}
fiatAmount = tokenFiatAmount,
fiatAmountFormatted = tokenFiatAmount?.toFormattedFiatValue(fiatCurrencySymbol)
),
pendingTransactions = tokenPendingTransactions.removeUnknownTransactions(),
mainButton = WalletMainButton.SendButton(sendButtonEnabled)
@ -110,8 +111,12 @@ class OnWalletLoadedReducer {
if (tokenAmount != null) {
val tokenFiatRate = walletState.primaryWallet?.currencyData?.token?.fiatRate
val tokenFiatAmount = tokenFiatRate?.let { tokenAmount.value?.toFiatString(it, fiatCurrencySymbol) }
TokenData(tokenAmount.value?.toFormattedString(tokenAmount.decimals) ?: "",
tokenAmount.currencySymbol, tokenFiatAmount)
TokenData(
tokenAmount.value?.toFormattedCurrencyString(
token.decimals, token.symbol
) ?: "",
tokenAmount.currencySymbol, tokenFiatAmount
)
} else {
null
}
@ -141,8 +146,8 @@ class OnWalletLoadedReducer {
currencySymbol = wallet.blockchain.currency,
formattedAmount,
token = tokenData,
fiatAmount = fiatAmount,
fiatAmountRaw = fiatAmountRaw
fiatAmountFormatted = fiatAmount,
fiatAmount = fiatAmountRaw
),
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
mainButton = WalletMainButton.SendButton(sendButtonEnabled)

View file

@ -1,15 +1,11 @@
package com.tangem.tap.features.wallet.redux.reducers
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Wallet
import com.tangem.commands.common.network.TangemService
import com.tangem.common.extensions.toHexString
import com.tangem.tap.common.extensions.toFiatString
import com.tangem.tap.common.extensions.toFormattedCurrencyString
import com.tangem.tap.common.extensions.toQrCode
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.common.redux.global.FiatCurrencyName
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.getFirstToken
@ -88,7 +84,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
)
}
is WalletAction.LoadWallet -> {
if (action.currency == null) {
if (action.blockchain == null) {
val wallets = newState.wallets.map { wallet ->
wallet.copy(
currencyData = wallet.currencyData.copy(
@ -106,9 +102,12 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
wallets = wallets
)
} else {
val walletManager = newState.getWalletManager(action.currency) ?: return newState
val currencies = listOf(walletManager.wallet.blockchain.currency) + walletManager.presetTokens.map { it.symbol }
val newWallets = newState.wallets.filter { currencies.contains(it.currencyData.currencySymbol) }
val walletManager = newState.getWalletManager(action.blockchain) ?: return newState
val blockchain = walletManager.wallet.blockchain
val currencies = listOf(Currency.Blockchain(blockchain)) + walletManager.presetTokens.map {
Currency.Token(token = it, blockchain = blockchain)
}
val newWallets = newState.wallets.filter { currencies.contains(it.currency) }
.map { wallet ->
wallet.copy(
currencyData = wallet.currencyData.copy(
@ -131,7 +130,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
newState = onWalletLoadedReducer.reduce(action.wallet, newState)
}
is WalletAction.LoadWallet.NoAccount -> {
val walletData = newState.getWalletData(action.wallet.blockchain.currency)?.copy(
val walletData = newState.getWalletData(action.wallet.blockchain)?.copy(
currencyData = BalanceWidgetData(
BalanceStatus.NoAccount, action.wallet.blockchain.fullName,
currencySymbol = action.wallet.blockchain.currency,
@ -155,7 +154,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
} else {
action.errorMessage
}
val walletData = newState.getWalletData(action.wallet.blockchain.currency)
val walletData = newState.getWalletData(action.wallet.blockchain)
val newWalletData = walletData?.copy(
currencyData = walletData.currencyData.copy(
status = BalanceStatus.Unreachable,
@ -164,7 +163,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
topUpState = TopUpState(false)
)
val tokenWallets = action.wallet.getTokens()
.mapNotNull { newState.getWalletData(it.symbol) }
.mapNotNull { newState.getWalletData(it) }
.map {
it.copy(currencyData = it.currencyData.copy(
status = BalanceStatus.Unreachable, errorMessage = message
@ -241,7 +240,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
is WalletAction.ChangeSelectedAddress -> {
val selectedWalletData = newState.getWalletData(newState.selectedWallet)
val walletAddresses = newState.getWalletData(selectedWalletData?.currencyData?.currencySymbol)?.walletAddresses
val walletAddresses = newState.getWalletData(selectedWalletData?.currency)?.walletAddresses
?: return newState
val address = walletAddresses.list.firstOrNull { it.type == action.type }
?: return newState
@ -288,64 +287,60 @@ private fun handleCheckSignedHashesActions(action: WalletAction.Warnings, state:
private fun setNewFiatRate(
fiatRate: Pair<CryptoCurrencyName, BigDecimal?>,
fiatRate: Pair<Currency, BigDecimal?>,
appCurrency: FiatCurrencyName, state: WalletState
): WalletState {
val rate = fiatRate.second ?: return state
val rateFormatted = rate.toFormattedCurrencyString(2, appCurrency)
val currency = fiatRate.first
if (!state.isMultiwalletAllowed) {
return setSingeWalletFiatRate(rate, rateFormatted, currency, appCurrency, state)
return if (!state.isMultiwalletAllowed) {
setSingeWalletFiatRate(rate, rateFormatted, currency, appCurrency, state)
} else {
return setMultiWalletFiatRate(rate, rateFormatted, currency, appCurrency, state)
setMultiWalletFiatRate(rate, rateFormatted, currency, appCurrency, state)
}
}
private fun setMultiWalletFiatRate(
rate: BigDecimal, rateFormatted: String, currency: CryptoCurrencyName,
appCurrency: FiatCurrencyName, state: WalletState
rate: BigDecimal, rateFormatted: String, currency: Currency,
appCurrency: FiatCurrencyName, state: WalletState
): WalletState {
val walletData = state.getWalletData(currency) ?: return state
val wallet = state.walletManagers.find { it.wallet.blockchain.currency == currency }?.wallet
if (wallet != null) {
val newWalletData = state.getWalletData(currency)?.copy(
currencyData = walletData.currencyData.copy(
fiatAmount = wallet.amounts[AmountType.Coin]?.value
?.toFiatString(rate, appCurrency)),
fiatRate = rate, fiatRateString = rateFormatted
)
return state.copy(wallets = state.replaceWalletInWallets(newWalletData))
} else {
val ethereumWallet = state.walletManagers.find { it.wallet.blockchain == Blockchain.Ethereum }?.wallet
val token = ethereumWallet?.getTokens()?.find { it.symbol == currency } ?: return state
val tokenFiatAmount = ethereumWallet.getTokenAmount(token)?.value?.toFiatString(rate, appCurrency)
val newWalletData = state.getWalletData(currency)?.copy(
currencyData = walletData.currencyData.copy(
fiatAmount = tokenFiatAmount),
fiatRate = rate, fiatRateString = rateFormatted
)
return state.copy(wallets = state.replaceWalletInWallets(newWalletData))
val wallet = state.getWalletManager(currency)?.wallet
val fiatAmount = when (currency) {
is Currency.Blockchain ->
wallet?.amounts?.get(AmountType.Coin)?.value?.toFiatValue(rate)
is Currency.Token ->
wallet?.getTokenAmount(currency.token)?.value?.toFiatValue(rate)
}
val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(appCurrency)
val newWalletData = state.getWalletData(currency)?.copy(
currencyData = walletData.currencyData.copy(
fiatAmountFormatted = fiatAmountFormatted,
fiatAmount = fiatAmount
),
fiatRate = rate, fiatRateString = rateFormatted
)
return state.copy(wallets = state.replaceWalletInWallets(newWalletData))
}
private fun setSingeWalletFiatRate(
rate: BigDecimal, rateFormatted: String, currency: CryptoCurrencyName,
rate: BigDecimal, rateFormatted: String, currency: Currency,
appCurrency: FiatCurrencyName, state: WalletState
): WalletState {
val wallet = state.walletManagers[0].wallet
val token = wallet.getFirstToken()
if (currency == state.primaryWallet?.currencyData?.currencySymbol) {
if (currency == state.primaryWallet?.currency) {
val fiatAmount = wallet.amounts[AmountType.Coin]?.value
?.toFiatString(rate, appCurrency)
val walletData = state.primaryWallet.copy(
currencyData = state.primaryWallet.currencyData.copy(fiatAmount = fiatAmount),
currencyData = state.primaryWallet.currencyData.copy(fiatAmountFormatted = fiatAmount),
fiatRate = rate,
fiatRateString = rateFormatted
)
return state.copy(wallets = listOf(walletData))
} else if (currency == token?.symbol) {
} else if (currency is Currency.Token && currency.token == token) {
val tokenFiatAmount = wallet.getTokenAmount(token)?.value?.toFiatString(rate, appCurrency)
val tokenData = state.primaryWallet?.currencyData?.token?.copy(
fiatAmount = tokenFiatAmount,

View file

@ -22,15 +22,15 @@ enum class BalanceStatus {
}
data class BalanceWidgetData(
val status: BalanceStatus? = null,
val currency: String? = null,
val currencySymbol: String? = null,
val amount: String? = null,
val fiatAmount: String? = null,
val fiatAmountRaw: BigDecimal? = null,
val token: TokenData? = null,
val amountToCreateAccount: String? = null,
val errorMessage: String? = null
val status: BalanceStatus? = null,
val currency: String? = null,
val currencySymbol: String? = null,
val amount: String? = null,
val fiatAmountFormatted: String? = null,
val fiatAmount: BigDecimal? = null,
val token: TokenData? = null,
val amountToCreateAccount: String? = null,
val errorMessage: String? = null
)
data class TokenData(
@ -158,7 +158,7 @@ class BalanceWidget(
fragment.tv_amount.text = if (showAmount) data.amount else ""
if (showAmount) {
fragment.tv_fiat_amount.show()
fragment.tv_fiat_amount.text = data.fiatAmount
fragment.tv_fiat_amount.text = data.fiatAmountFormatted
}
}
}

View file

@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.transition.TransitionInflater
import com.squareup.picasso.Picasso
import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.MainActivity
import com.tangem.tap.common.extensions.*
@ -24,6 +25,9 @@ import kotlinx.android.synthetic.main.fragment_details_twin_cards.*
import kotlinx.android.synthetic.main.fragment_wallet_details.*
import kotlinx.android.synthetic.main.fragment_wallet_details.toolbar
import kotlinx.android.synthetic.main.item_currency_wallet.view.*
import kotlinx.android.synthetic.main.item_currency_wallet.view.iv_currency
import kotlinx.android.synthetic.main.item_currency_wallet.view.tv_token_letter
import kotlinx.android.synthetic.main.item_popular_token.view.*
import kotlinx.android.synthetic.main.layout_balance_error.*
import kotlinx.android.synthetic.main.layout_balance_wallet_details.*
import kotlinx.android.synthetic.main.layout_wallet_details.*
@ -123,7 +127,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
if (selectedWallet.currencyData.status != BalanceStatus.Loading) {
store.dispatch(WalletAction.LoadWallet(
selectedWallet.topUpState.allowed,
selectedWallet.currencyData.currencySymbol
selectedWallet.currency?.blockchain
))
}
}
@ -134,16 +138,12 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
}
private fun handleCurrencyIcon(wallet: WalletData) {
val blockchain = wallet.currencyData.currencySymbol?.let { Blockchain.fromCurrency(it) }
if (blockchain != null && blockchain != Blockchain.Unknown) {
tv_token_letter.text = null
iv_currency.colorFilter = null
iv_currency.setImageResource(blockchain.getIconRes())
} else {
tv_token_letter.text = wallet.currencyData.currencySymbol?.take(1)
wallet.token?.getColor()?.let { iv_currency.setColorFilter(it) }
iv_currency.setImageResource(R.drawable.shape_circle)
}
Picasso.get().loadCurrenciesIcon(
imageView = iv_currency,
textView = tv_token_letter,
blockchain = wallet.currency?.blockchain,
token = (wallet.currency as? Currency.Token)?.token
)
}
@ -154,7 +154,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
private fun setupAddressCard(state: WalletData) {
if (state.walletAddresses != null) {
if (state.shouldShowMultipleAddress() && state.blockchain != null) {
if (state.shouldShowMultipleAddress() && state.currency is Currency.Blockchain) {
(card_balance as? ViewGroup)?.beginDelayedTransition()
chip_group_address_type.show()
chip_group_address_type.fitChipsByGroupWidth()
@ -164,7 +164,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
if (checkedId == -1) return@setOnCheckedChangeListener
val type = MultipleAddressUiHelper.idToType(checkedId, state.blockchain)
val type = MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain)
type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) }
}
} else {
@ -260,7 +260,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
tv_amount.text = if (showAmount) data.amount else ""
if (showAmount) {
tv_fiat_amount.show()
tv_fiat_amount.text = data.fiatAmount
tv_fiat_amount.text = data.fiatAmountFormatted
}
}

View file

@ -8,6 +8,7 @@ import android.view.MenuItem
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.get
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -106,7 +107,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
if (!state.shouldShowDetails) {
toolbar.menu.removeItem(R.id.details_menu)
} else if (toolbar.menu.findItem(R.id.details_menu) == null) {
toolbar.menu.add(R.menu.wallet, R.id.details_menu, NONE, R.string.details_title)
toolbar.inflateMenu(R.menu.wallet)
}
setupNoInternetHandling(state)

View file

@ -6,15 +6,12 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Callback
import com.squareup.picasso.Picasso
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.IconsUtil
import com.tangem.blockchain.common.Token
import com.tangem.tap.common.extensions.getColor
import com.tangem.tap.common.extensions.getIconRes
import com.tangem.tap.common.extensions.loadCurrenciesIcon
import com.tangem.tap.common.extensions.show
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.ui.BalanceStatus
@ -24,8 +21,6 @@ import kotlinx.android.synthetic.main.item_currency_wallet.view.*
import kotlinx.android.synthetic.main.item_currency_wallet.view.iv_currency
import kotlinx.android.synthetic.main.item_currency_wallet.view.tv_currency_symbol
import kotlinx.android.synthetic.main.item_currency_wallet.view.tv_token_letter
import kotlinx.android.synthetic.main.item_popular_token.view.*
import java.lang.Exception
import java.math.BigDecimal
class WalletAdapter
@ -38,7 +33,9 @@ class WalletAdapter
fun submitList(list: List<WalletData>, primaryBlockchain: Blockchain?, primaryToken: Token? = null) {
val listModified = list.toMutableList()
val primaryBlockchainWallet = when (
val index = listModified.indexOfFirst { it.blockchain == primaryBlockchain }
val index = listModified.indexOfFirst {
(it.currency as? Currency.Blockchain)?.blockchain == primaryBlockchain
}
) {
-1 -> null
else -> listModified.removeAt(index)
@ -46,20 +43,20 @@ class WalletAdapter
val primaryTokenWallet = if (primaryToken == null) null else when (
val index = listModified.indexOfFirst { it.token == primaryToken }
val index = listModified.indexOfFirst { (it.currency as? Currency.Token)?.token == primaryToken }
) {
-1 -> null
else -> listModified.removeAt(index)
}
if (list.all { it.currencyData.fiatAmount == null }) {
if (list.all { it.currencyData.fiatAmountFormatted == null }) {
val sortedList = listOfNotNull(primaryBlockchainWallet, primaryTokenWallet) + listModified
super.submitList(sortedList)
return
}
val sorted = listModified.sortedWith(
compareByDescending<WalletData> { it.currencyData.fiatAmountRaw ?: BigDecimal.ZERO }
compareByDescending<WalletData> { it.currencyData.fiatAmount ?: BigDecimal.ZERO }
.thenBy { it.currencyData.currencySymbol }
)
val sortedList = listOfNotNull(primaryBlockchainWallet, primaryTokenWallet) + sorted
@ -93,13 +90,13 @@ class WalletAdapter
view.tv_currency.text = wallet.currencyData.currency
view.tv_amount.text = wallet.currencyData.amount?.takeWhile { !it.isWhitespace() }
view.tv_currency_symbol.text = wallet.currencyData.amount?.takeLastWhile { !it.isWhitespace() }
view.tv_amount_fiat.text = wallet.currencyData.fiatAmount
view.tv_amount_fiat.text = wallet.currencyData.fiatAmountFormatted
view.tv_exchange_rate.text = wallet.fiatRateString
view.card_wallet.setOnClickListener {
store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet))
}
val blockchain = wallet.blockchain
val token = wallet.token
val blockchain = wallet.currency?.blockchain
val token = (wallet.currency as? Currency.Token)?.token
Picasso.get().loadCurrenciesIcon(
imageView = view.iv_currency,

View file

@ -190,7 +190,7 @@ class SingleWalletView : WalletView {
private fun setupAddressCard(state: WalletData, fragment: WalletFragment) = with(fragment) {
if (state.walletAddresses != null && state.blockchain != null) {
if (state.walletAddresses != null && state.currency is Currency.Blockchain) {
l_address?.show()
if (state.shouldShowMultipleAddress()) {
(l_address as? ViewGroup)?.beginDelayedTransition()
@ -202,7 +202,7 @@ class SingleWalletView : WalletView {
chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
if (checkedId == -1) return@setOnCheckedChangeListener
val type = MultipleAddressUiHelper.idToType(checkedId, state.blockchain)
val type = MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain)
type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) }
}
} else {

View file

@ -19,7 +19,6 @@ buildscript {
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
def nexusUser = "viewer"
def nexusPass = "smartcash124"

View file

@ -1,4 +1,4 @@
ext.versions = [
kotlin : '1.5.0',
build_gradle: '4.2.0',
build_gradle: '4.2.1',
]