Updated on 2026-08-14

This commit is contained in:
Tangem 2023-02-12 17:54:10 +03:00
parent b153993f3c
commit 5a20f6d533
22 changed files with 387 additions and 429 deletions

View file

@ -210,6 +210,7 @@ fun View.animateVisibility(
hiddenVisibility: Int = View.GONE,
) {
if (show) {
if (this.visibility == View.VISIBLE) return
this.animate()
.alpha(1f)
.setDuration(durationMillis)
@ -218,6 +219,7 @@ fun View.animateVisibility(
this.isVisible = true
}
} else {
if (this.visibility == hiddenVisibility) return
this.animate()
.alpha(0f)
.setDuration(durationMillis)

View file

@ -1,5 +1,6 @@
package com.tangem.tap.domain
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.blockchain.common.Token
@ -39,6 +40,7 @@ import com.tangem.tap.userTokensRepository
import com.tangem.tap.walletStoresManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.rekotlin.Action
import timber.log.Timber
class TapWalletManager {
@ -223,20 +225,20 @@ class TapWalletManager {
val primaryWalletManager = walletManagerFactory.makePrimaryWalletManager(data)
if (blockchain != Blockchain.Unknown && primaryWalletManager != null) {
val primaryToken = data.getPrimaryToken()
dispatchOnMain(WalletAction.MultiWallet.SetPrimaryBlockchain(blockchain))
if (primaryToken != null) {
primaryWalletManager.addToken(primaryToken)
dispatchOnMain(WalletAction.MultiWallet.SetPrimaryToken(primaryToken))
}
dispatchOnMain(
val blockchainNetwork = BlockchainNetwork.fromWalletManager(primaryWalletManager)
val actionsList = listOfNotNull<Action>(
WalletAction.MultiWallet.AddBlockchains(
blockchains = listOf(BlockchainNetwork.fromWalletManager(primaryWalletManager)),
walletManagers = listOf(primaryWalletManager),
),
data.getPrimaryToken()?.let {
primaryWalletManager.addToken(it)
primaryWalletManager.wallet.setAmount(Amount(it))
WalletAction.MultiWallet.AddToken(it, blockchainNetwork, false)
},
WalletAction.LoadFiatRate(),
)
dispatchOnMain(*actionsList.toTypedArray())
}
}

View file

@ -2,7 +2,6 @@ package com.tangem.tap.features.wallet.redux
import android.content.Context
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
@ -98,8 +97,6 @@ sealed class WalletAction : Action {
data class RemoveWallet(val currency: Currency) : MultiWallet()
data class RemoveWallets(val currencies: List<Currency>) : MultiWallet()
data class SetPrimaryBlockchain(val blockchain: Blockchain) : MultiWallet()
data class SetPrimaryToken(val token: Token) : MultiWallet()
data class ShowWalletBackupWarning(val show: Boolean) : MultiWallet()
object BackupWallet : MultiWallet()
object ScheduleCheckForMissingDerivation : MultiWallet()

View file

@ -12,6 +12,7 @@ import com.tangem.tap.common.extensions.toQrCode
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.common.toggleWidget.WidgetState
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
import com.tangem.tap.features.wallet.models.Currency
@ -43,8 +44,6 @@ data class WalletState(
val isMultiwalletAllowed: Boolean = false,
val cardCurrency: CryptoCurrencyName? = null,
val selectedCurrency: Currency? = null,
val primaryBlockchain: Blockchain? = null,
val primaryToken: Token? = null,
val isTestnet: Boolean = false,
val totalBalance: TotalBalance? = null,
val showBackupWarning: Boolean = false,
@ -81,13 +80,30 @@ data class WalletState(
val walletManagers: List<WalletManager>
get() = walletsStores.mapNotNull { it.walletManager }
val primaryWallet: WalletData? = walletsStores.firstOrNull()?.walletsData?.firstOrNull()
private val primaryWalletStore: WalletStore?
get() = if (isMultiwalletAllowed || walletsStores.isEmpty() || walletsStores.size > 1) null
else walletsStores[0]
val primaryWalletManager: WalletManager? = if (walletsStores.isNotEmpty()) walletsStores[0].walletManager else null
private val primaryWalletManager: WalletManager?
get() = primaryWalletStore?.walletManager
val primaryWalletData: WalletData?
get() = primaryWalletStore?.walletsData?.firstOrNull()
val primaryBlockchain: Blockchain?
get() = primaryWalletManager?.wallet?.blockchain
val primaryToken: Token?
get() = primaryWalletManager?.wallet?.getFirstToken()
val primaryTokenData: WalletData?
get() = primaryWalletStore?.walletsData?.toMutableList()
?.apply { remove(primaryWalletData) }
?.firstOrNull()
val shouldShowDetails: Boolean =
primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain
primaryWalletData?.currencyData?.status != BalanceStatus.EmptyCard &&
primaryWalletData?.currencyData?.status != BalanceStatus.UnknownBlockchain
val hasSavedWallets: Boolean
get() = userWalletsListManager.hasSavedUserWallets
@ -138,13 +154,6 @@ data class WalletState(
return getWalletStore(currency)?.walletsData?.firstOrNull { it.currency == currency }
}
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 replaceWalletStoreInWalletsStores(wallet: WalletStore?): List<WalletStore> {
if (wallet == null) return walletsStores
var changed = false

View file

@ -1,6 +1,5 @@
package com.tangem.tap.features.wallet.redux.middlewares
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.isZero
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.common.extensions.toFiatRateString
@ -19,7 +18,6 @@ import com.tangem.tap.features.wallet.redux.WalletMainButton
import com.tangem.tap.features.wallet.redux.WalletStore
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.features.wallet.ui.TokenData
import com.tangem.tap.store
import java.math.BigDecimal
@ -49,15 +47,6 @@ internal fun WalletStoreModel.mapToReduxModel(): WalletStore {
walletsData = walletsData.mapToReduxModels(walletRent, appCurrencySymbol),
)
.updateTokenModels(blockchainWalletData.status.amount)
.setupIfHadCardSingleToken(
blockchain = blockchain,
walletsDataModel = walletsData,
appCurrencySymbol = appCurrencySymbol,
blockchainWalletData = blockchainWalletData.mapToReduxModel(
walletRent = walletRent,
appCurrencySymbol = appCurrencySymbol,
),
)
}
private fun List<WalletDataModel>.mapToReduxModels(
@ -122,7 +111,7 @@ private fun WalletDataModel.mapToReduxModel(
amountFormatted = amountFormatted,
fiatAmount = fiatAmount,
fiatAmountFormatted = fiatAmountFormatted,
token = null,
// token = null,
amountToCreateAccount = (status as? WalletDataModel.NoAccount)
?.amountToCreateAccount
?.toString(),
@ -146,45 +135,4 @@ private fun WalletStore.updateTokenModels(blockchainAmount: BigDecimal): WalletS
)
}
return updateWallets(updatedTokensWalletData)
}
private fun WalletStore.setupIfHadCardSingleToken(
blockchain: Blockchain,
walletsDataModel: List<WalletDataModel>,
appCurrencySymbol: String,
blockchainWalletData: WalletData,
): WalletStore {
// Card with single token contains only 2 model - blockchain and token
if (walletsData.size != 2) return this
val cardSingleTokenWalletData = walletsDataModel.firstOrNull {
it.currency.isToken() && it.currency.blockchain == blockchain && it.isCardSingleToken
} ?: return this
val blockchainWalletDataWithSingleToken = blockchainWalletData.copy(
currencyData = blockchainWalletData.currencyData.copy(
token = cardSingleTokenWalletData.toTokenData(appCurrencySymbol),
),
)
return updateWallets(listOf(blockchainWalletDataWithSingleToken))
}
private fun WalletDataModel.toTokenData(appCurrencySymbol: String): TokenData {
val amount = status.amount
val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) }
return TokenData(
amount = amount,
amountFormatted = amount.toFormattedCurrencyString(
decimals = currency.decimals,
currency = currency.currencySymbol,
),
fiatAmount = fiatAmount,
fiatAmountFormatted = fiatAmount
?.takeIf { !status.isErrorStatus }
?.toFormattedFiatValue(appCurrencySymbol),
tokenSymbol = currency.currencySymbol,
fiatRate = fiatRate,
fiatRateString = fiatRate?.toFiatRateString(appCurrencySymbol),
)
}

View file

@ -49,6 +49,7 @@ 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.features.wallet.redux.reducers.findSelectedCurrency
import com.tangem.tap.network.NetworkConnectivity
import com.tangem.tap.network.NetworkStateChanged
import com.tangem.tap.preferencesStorage
@ -153,7 +154,7 @@ class WalletMiddleware {
if (walletState.isMultiwalletAllowed) {
walletState.walletsDataFromStores.map { it.currency }
} else {
val derivationPath = walletState.primaryWallet?.currency?.derivationPath
val derivationPath = walletState.primaryWalletData?.currency?.derivationPath
val primaryBlockchain = walletState.primaryBlockchain
val primaryToken = walletState.primaryToken
listOfNotNull(
@ -310,15 +311,14 @@ class WalletMiddleware {
}
}
private fun updateWalletStores(wallStores: List<WalletStoreModel>, state: WalletState) {
private fun updateWalletStores(walletsStores: List<WalletStoreModel>, state: WalletState) {
scope.launch(Dispatchers.Default) {
val reduxWalletStores = walletsStores.mapToReduxModels()
if (!state.isMultiwalletAllowed) {
wallStores.firstOrNull()?.walletsData?.firstOrNull()?.let {
store.dispatchOnMain(WalletAction.MultiWallet.SetSingleWalletCurrency(it.currency))
findSelectedCurrency(reduxWalletStores, null, false)?.let {
store.dispatchOnMain(WalletAction.MultiWallet.SetSingleWalletCurrency(it))
}
}
val reduxWalletStores = wallStores.mapToReduxModels()
store.dispatchOnMain(
WalletAction.WalletStoresChanged.UpdateWalletStores(
reduxWalletStores = reduxWalletStores,
@ -438,11 +438,7 @@ class WalletMiddleware {
walletStore: WalletStore?,
): PrepareSendScreen {
val coinRate = state?.getWalletData(walletStore?.blockchainNetwork)?.fiatRate
val tokenRate = if (state?.isMultiwalletAllowed == true) {
selectedWalletData?.fiatRate
} else {
selectedWalletData?.currencyData?.token?.fiatRate
}
val tokenRate = selectedWalletData?.fiatRate
val coinAmount = walletStore?.walletManager?.wallet?.amounts?.get(AmountType.Coin)
return PrepareSendScreen(

View file

@ -10,7 +10,6 @@ import com.tangem.tap.common.extensions.toFiatString
import com.tangem.tap.common.extensions.toFormattedCurrencyString
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.WalletRent
@ -26,7 +25,6 @@ import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT
import com.tangem.tap.features.wallet.redux.WalletStore
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.features.wallet.ui.TokenData
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
import com.tangem.wallet.R
@ -42,17 +40,11 @@ class MultiWalletReducer {
(it.wallet.publicKey.derivationPath?.rawPath == blockchain.derivationPath)
}
val wallet = walletManager?.wallet
val cardToken = if (!state.isMultiwalletAllowed) {
wallet?.getFirstToken()?.symbol?.let { TokenData("", tokenSymbol = it) }
} else {
null
}
val walletData = WalletData(
currencyData = BalanceWidgetData(
status = BalanceStatus.Loading,
currency = blockchain.blockchain.fullName,
currencySymbol = blockchain.blockchain.currency,
token = cardToken,
),
walletAddresses = createAddressList(wallet),
mainButton = WalletMainButton.SendButton(false),
@ -66,18 +58,17 @@ class MultiWalletReducer {
WalletStore(
walletManager = walletManager,
blockchainNetwork = blockchain,
walletsData = listOf(walletData),
walletsData = listOfNotNull(walletData),
)
}
val selectedCurrency = if (state.isMultiwalletAllowed) {
state.selectedCurrency
} else {
walletStores.firstOrNull()?.walletsData?.firstOrNull()?.currency
}
state.copy(
walletsStores = walletStores,
selectedCurrency = selectedCurrency,
selectedCurrency = findSelectedCurrency(
walletsStores = walletStores,
currentSelectedCurrency = state.selectedCurrency,
isMultiWalletAllowed = state.isMultiwalletAllowed,
),
)
}
is WalletAction.MultiWallet.AddBlockchain -> {
@ -181,8 +172,6 @@ class MultiWalletReducer {
action.currencies.forEach { updatedState = updatedState.removeWalletData(state.getWalletData(it)) }
updatedState
}
is WalletAction.MultiWallet.SetPrimaryBlockchain -> state.copy(primaryBlockchain = action.blockchain)
is WalletAction.MultiWallet.SetPrimaryToken -> state.copy(primaryToken = action.token)
is WalletAction.MultiWallet.SaveCurrencies -> state
is WalletAction.MultiWallet.ShowWalletBackupWarning -> state.copy(showBackupWarning = action.show)
is WalletAction.MultiWallet.ScheduleCheckForMissingDerivation -> state.copy(
@ -190,7 +179,7 @@ class MultiWalletReducer {
)
is WalletAction.MultiWallet.AddMissingDerivations -> state.copy(
missingDerivations = action.blockchains,
derivationsCheckIsScheduled = false
derivationsCheckIsScheduled = false,
)
is WalletAction.MultiWallet.BackupWallet -> state
is WalletAction.MultiWallet.ScanToGetDerivations -> state.copy(state = ProgressState.Loading)
@ -212,7 +201,6 @@ class MultiWalletReducer {
}
fun Token.toWallet(state: WalletState, blockchain: BlockchainNetwork): WalletData? {
if (!state.isMultiwalletAllowed) return null
val currency = Currency.fromBlockchainNetwork(blockchain, this)
if (state.currencies.contains(currency)) return null

View file

@ -3,11 +3,9 @@ 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.toFiatValue
import com.tangem.tap.common.extensions.toFormattedCurrencyString
import com.tangem.tap.common.extensions.toFormattedFiatValue
import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.filterByToken
@ -20,9 +18,7 @@ import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT
import com.tangem.tap.features.wallet.redux.replaceSomeWalletsData
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.features.wallet.ui.TokenData
import com.tangem.tap.store
import java.math.BigDecimal
class OnWalletLoadedReducer {
@ -37,7 +33,7 @@ class OnWalletLoadedReducer {
private fun onMultiWalletLoaded(
wallet: Wallet,
blockchainNetwork: BlockchainNetwork,
walletState: WalletState
walletState: WalletState,
): WalletState {
val walletData = walletState.getWalletData(blockchainNetwork) ?: return walletState
@ -45,7 +41,7 @@ class OnWalletLoadedReducer {
val coinAmountValue = wallet.amounts[AmountType.Coin]?.value
val formattedAmount = coinAmountValue?.toFormattedCurrencyString(
wallet.blockchain.decimals(),
wallet.blockchain.currency
wallet.blockchain.currency,
)
val pendingTransactions = wallet.getPendingTransactions()
@ -98,7 +94,7 @@ class OnWalletLoadedReducer {
amount = tokenAmountValue,
amountFormatted = tokenAmountValue?.toFormattedCurrencyString(
token.decimals,
token.symbol
token.symbol,
),
fiatAmount = tokenFiatAmount,
fiatAmountFormatted = tokenFiatAmountFormatted,
@ -117,33 +113,12 @@ class OnWalletLoadedReducer {
if (wallet.blockchain != walletState.primaryBlockchain) return walletState
val fiatCurrencyName = store.state.globalState.appCurrency.code
val token = wallet.getFirstToken()
val tokenData = if (token != null) {
val tokenAmount = wallet.getTokenAmount(token)
if (tokenAmount != null) {
val tokenFiatRate = walletState.primaryWallet?.currencyData?.token?.fiatRate
val tokenFiatAmount =
tokenFiatRate?.let { tokenAmount.value?.toFiatString(it, fiatCurrencyName) }
TokenData(
amount = tokenAmount.value ?: BigDecimal.ZERO,
tokenSymbol = tokenAmount.currencySymbol, fiatAmountFormatted = tokenFiatAmount,
fiatAmount = tokenFiatRate?.let { tokenAmount.value?.toFiatValue(tokenFiatRate) },
amountFormatted = tokenAmount.value?.toFormattedCurrencyString(
token.decimals, token.symbol,
) ?: "",
)
} else {
null
}
} else {
null
}
val amount = wallet.amounts[AmountType.Coin]?.value
val formattedAmount = amount?.toFormattedCurrencyString(
wallet.blockchain.decimals(),
wallet.blockchain.currency
wallet.blockchain.currency,
)
val fiatAmount = walletState.primaryWallet?.fiatRate?.let { amount?.toFiatValue(it) }
val fiatAmount = walletState.primaryWalletData?.fiatRate?.let { amount?.toFiatValue(it) }
val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(fiatCurrencyName) ?: UNKNOWN_AMOUNT_SIGN
val pendingTransactions = wallet.getPendingTransactions()
@ -153,16 +128,15 @@ class OnWalletLoadedReducer {
} else {
BalanceStatus.VerifiedOnline
}
val walletData = walletState.primaryWallet?.copy(
val walletData = walletState.primaryWalletData?.copy(
currencyData = BalanceWidgetData(
balanceStatus, wallet.blockchain.fullName,
currencySymbol = wallet.blockchain.currency,
token = tokenData,
blockchainAmount = amount,
amount = amount,
amountFormatted = formattedAmount,
fiatAmount = fiatAmount,
fiatAmountFormatted = fiatAmountFormatted
fiatAmountFormatted = fiatAmountFormatted,
),
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
mainButton = WalletMainButton.SendButton(sendButtonEnabled),
@ -171,7 +145,8 @@ class OnWalletLoadedReducer {
val updatedStore = walletState.getWalletStore(walletData?.currency)?.updateWallets(wallets)
return walletState.updateWalletStore(updatedStore).copy(
state = ProgressState.Done, error = null
state = ProgressState.Done,
error = null,
)
}
}

View file

@ -9,7 +9,6 @@ import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.TwinCardNumber
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
@ -17,7 +16,6 @@ import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.extensions.getArtworkUrl
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.WalletRent
@ -36,7 +34,6 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.proxy.AppStateHolder
import org.rekotlin.Action
import timber.log.Timber
import java.math.BigDecimal
class WalletReducer {
@ -285,8 +282,9 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS
newState = newState.copy(cardImage = cardImage)
}
is WalletAction.LoadFiatRate.Success ->
is WalletAction.LoadFiatRate.Success -> {
newState = setNewFiatRate(action.fiatRates, state.globalState.appCurrency, newState)
}
is WalletAction.LoadArtwork -> {
val artworkUrl = action.card.getArtworkUrl(action.artworkId)
?: when (state.twinCardsState.cardNumber) {
@ -361,18 +359,13 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS
)
}
is WalletAction.LoadData.Success -> {
val selectedCurrency = if (newState.isMultiwalletAllowed) {
newState.selectedCurrency
} else {
newState.walletsStores.firstOrNull()
?.walletsData
?.firstOrNull()
?.currency
}
newState = newState.copy(
state = ProgressState.Done,
selectedCurrency = selectedCurrency,
selectedCurrency = findSelectedCurrency(
walletsStores = newState.walletsStores,
currentSelectedCurrency = newState.selectedCurrency,
isMultiWalletAllowed = newState.isMultiwalletAllowed,
),
)
}
else -> Unit
@ -381,6 +374,19 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS
return newState
}
fun findSelectedCurrency(
walletsStores: List<WalletStore>,
currentSelectedCurrency: Currency?,
isMultiWalletAllowed: Boolean,
): Currency? = if (isMultiWalletAllowed) {
currentSelectedCurrency
} else {
walletsStores.firstOrNull()
?.walletsData
?.firstOrNull()
?.currency
}
private fun CardDTO.findCardsCount(): Int? {
return (this.backupStatus as? CardDTO.BackupStatus.Active)?.cardCount?.inc()
?.takeIf { this.isMultiwalletAllowed }
@ -439,45 +445,18 @@ private fun setNewFiatRate(
state: WalletState,
): WalletState {
val rateFormatter: (BigDecimal) -> String = { rate: BigDecimal ->
rate.toFiatRateString(
fiatCurrencyName = appCurrency.symbol,
)
rate.toFiatRateString(fiatCurrencyName = appCurrency.symbol)
}
return if (state.isMultiwalletAllowed) {
setMultiWalletFiatRate(
fiatRates = fiatRates.mapNotNullValues { it.value },
rateFormatter = rateFormatter,
appCurrency = appCurrency,
state = state,
)
} else {
setSingleWalletFiatRates(
fiatRates = fiatRates.mapNotNullValues { it.value },
rateFormatter = rateFormatter,
appCurrency = appCurrency,
state = state,
)
}
}
private fun setMultiWalletFiatRate(
fiatRates: Map<Currency, BigDecimal>,
rateFormatter: (BigDecimal) -> String,
appCurrency: FiatCurrency,
state: WalletState,
): WalletState {
val newWalletsData = fiatRates.mapNotNull { (currency, rate) ->
val newWalletsData = fiatRates.mapNotNullValues { it.value }.mapNotNull { (currency, rate) ->
val walletStore = state.getWalletStore(currency) ?: return@mapNotNull null
val wallet = walletStore.walletManager?.wallet
val walletData = state.getWalletData(currency) ?: return@mapNotNull null
val currencyData = walletData.currencyData
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)
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.setScale(2)
@ -494,96 +473,5 @@ private fun setMultiWalletFiatRate(
)
}
return state
.updateWalletsData(newWalletsData)
}
private fun setSingleWalletFiatRates(
fiatRates: Map<Currency, BigDecimal>,
appCurrency: FiatCurrency,
rateFormatter: (BigDecimal) -> String,
state: WalletState,
): WalletState {
val blockchainFiatRate = fiatRates.entries.firstOrNull { it.key.isBlockchain() }
val tokenFiatRate = fiatRates.entries.firstOrNull { it.key.isToken() }
Timber.e("Token Fiat Rate is ${tokenFiatRate ?: "NULL"}")
val updatedState = updateStateWithFiatRate(blockchainFiatRate?.toPair(), appCurrency, rateFormatter, state)
return updateStateWithFiatRate(tokenFiatRate?.toPair(), appCurrency, rateFormatter, updatedState)
}
private fun updateStateWithFiatRate(
fiatRate: Pair<Currency, BigDecimal>?,
appCurrency: FiatCurrency,
rateFormatter: (BigDecimal) -> String,
state: WalletState,
): WalletState {
return if (fiatRate != null) {
val currency = fiatRate.first
val rate = fiatRate.second
setSingleWalletFiatRate(
rate = rate,
rateFormatted = rateFormatter(rate),
currency = currency,
appCurrency = appCurrency,
state = state,
)
} else {
state
}
}
private fun setSingleWalletFiatRate(
rate: BigDecimal,
rateFormatted: String,
currency: Currency,
appCurrency: FiatCurrency,
state: WalletState,
): WalletState {
val wallet = state.primaryWalletManager?.wallet ?: return state
val token = wallet.getFirstToken()
Timber.e("Working with currency: ${currency.currencyName}")
if (currency == state.primaryWallet?.currency) {
val fiatAmount = wallet.amounts[AmountType.Coin]?.value
?.toFiatString(rate, appCurrency.code)
val walletData = state.primaryWallet.copy(
currencyData = state.primaryWallet.currencyData.copy(fiatAmountFormatted = fiatAmount),
fiatRate = rate,
fiatRateString = rateFormatted,
)
return state.updateWalletData(walletData)
} else if (currency is Currency.Token && currency.token == token) {
Timber.e("Working with token fiat rate")
val tokenFiatAmount = wallet.getTokenAmount(token)
?.value
val tokenAmountFormatted = tokenFiatAmount?.toFiatString(rate, appCurrency.code)
val tokenData = state.primaryWallet?.currencyData?.token?.copy(
fiatAmountFormatted = tokenAmountFormatted,
fiatAmount = tokenFiatAmount,
fiatRate = rate,
fiatRateString = rateFormatted,
)
// ?: TokenData(
// fiatAmountFormatted = tokenAmountFormatted,
// fiatAmount = tokenFiatAmount,
// fiatRate = rate,
// fiatRateString = rateFormatted,
// amount = "",
// tokenSymbol = currency.currencySymbol
// )
Timber.e("Token Data is ${tokenData ?: "NULL"}")
val walletData = state.primaryWallet?.copy(
currencyData = state.primaryWallet.currencyData.copy(
token = tokenData,
),
)
Timber.e("Wallet Data is ${walletData ?: "NULL"}")
return state.updateWalletData(walletData)
}
return state
return state.updateWalletsData(newWalletsData)
}

View file

@ -24,31 +24,20 @@ data class BalanceWidgetData(
val status: BalanceStatus? = null,
val currency: String? = null,
val currencySymbol: String? = null,
val blockchainAmount: BigDecimal? = BigDecimal.ZERO,
val amount: BigDecimal? = null,
val amountFormatted: String? = null,
val fiatAmount: BigDecimal? = null,
val fiatAmountFormatted: String? = null,
val token: TokenData? = null,
val blockchainAmount: BigDecimal? = BigDecimal.ZERO,
val amountToCreateAccount: String? = null,
val errorMessage: String? = null
val errorMessage: String? = null,
)
data class TokenData(
val amountFormatted: String?,
val amount: BigDecimal? = null,
val tokenSymbol: String,
val fiatAmountFormatted: String? = null,
val fiatAmount: BigDecimal? = null,
val fiatRateString: String? = null,
val fiatRate: BigDecimal? = null,
)
class BalanceWidget(
private val binding: CardBalanceBinding,
private val fragment: WalletFragment,
private val data: BalanceWidgetData,
private val token: BalanceWidgetData?,
private val isTwinCard: Boolean,
) {
@ -68,7 +57,7 @@ class BalanceWidget(
showStatus(R.id.tv_status_loading)
if (data.token != null) {
if (token != null) {
showBalanceWithToken(data, false)
} else {
showBalanceWithoutToken(data, false)
@ -87,7 +76,7 @@ class BalanceWidget(
showStatus(statusView)
tvStatusErrorMessage.hide()
if (data.token != null) {
if (token != null) {
showBalanceWithToken(data, true)
} else {
showBalanceWithoutToken(data, true)
@ -99,7 +88,7 @@ class BalanceWidget(
tvFiatAmount.hide()
groupBaseCurrency.hide()
val currency = if (data.token != null) data.token.tokenSymbol else data.currency
val currency = if (token != null) token.currencySymbol else data.currency
tvCurrency.text = currency
tvAmount.text = ""
@ -130,7 +119,7 @@ class BalanceWidget(
tvErrorDescriptions.text =
fragment.getString(
R.string.no_account_generic,
data.amountToCreateAccount, data.currencySymbol
data.amountToCreateAccount, data.currencySymbol,
)
}
BalanceStatus.UnknownBlockchain -> with(binding.lBalanceError) {
@ -152,13 +141,13 @@ class BalanceWidget(
private fun showBalanceWithToken(data: BalanceWidgetData, showAmount: Boolean) = with(binding.lBalance) {
groupBaseCurrency.show()
tvCurrency.text = data.token?.tokenSymbol
tvCurrency.text = token?.currencySymbol
tvBaseCurrency.text = data.currency
tvAmount.text = if (showAmount) data.token?.amountFormatted else ""
tvAmount.text = if (showAmount) token?.amountFormatted else ""
tvBaseAmount.text = if (showAmount) data.amountFormatted else ""
if (showAmount) {
tvFiatAmount.show()
tvFiatAmount.text = data.token?.fiatAmountFormatted
tvFiatAmount.text = token?.fiatAmountFormatted
}
}

View file

@ -39,7 +39,7 @@ import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter
import com.tangem.tap.features.wallet.ui.wallet.MultiWalletView
import com.tangem.tap.features.wallet.ui.wallet.SaltPaySingleWalletView
import com.tangem.tap.features.wallet.ui.wallet.SaltPayWalletView
import com.tangem.tap.features.wallet.ui.wallet.SingleWalletView
import com.tangem.tap.features.wallet.ui.wallet.WalletView
import com.tangem.tap.store
@ -149,11 +149,11 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
val isSaltPay = store.state.globalState.scanResponse?.card?.isSaltPay == true
when {
isSaltPay && (walletView !is SaltPaySingleWalletView) -> {
walletView = SaltPaySingleWalletView()
isSaltPay && (walletView !is SaltPayWalletView) -> {
walletView = SaltPayWalletView()
walletView.changeWalletView(this, binding)
}
state.isMultiwalletAllowed && state.primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
state.isMultiwalletAllowed && state.primaryWalletData?.currencyData?.status != BalanceStatus.EmptyCard &&
walletView !is MultiWalletView -> {
walletView = MultiWalletView()
walletView.changeWalletView(this, binding)

View file

@ -88,6 +88,7 @@ class MultiWalletView : WalletView() {
private fun showMultiWalletView(binding: FragmentWalletBinding) = with(binding) {
watcher.clear()
lSaltPayWallet.root.hide()
tvTwinCardNumber.hide()
rvPendingTransaction.hide()
lCardBalance.root.hide()
@ -220,7 +221,7 @@ class MultiWalletView : WalletView() {
binding: FragmentWalletBinding,
fragment: WalletFragment,
) {
when (state.primaryWallet?.currencyData?.status) {
when (state.primaryWalletData?.currencyData?.status) {
BalanceStatus.EmptyCard -> {
showErrorState(
binding,

View file

@ -1,64 +0,0 @@
package com.tangem.tap.features.wallet.ui.wallet
import com.tangem.domain.common.extensions.debounce
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.animateVisibility
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.mainScope
import com.tangem.tap.store
import com.tangem.wallet.databinding.LayoutSingleWalletBalanceBinding
import org.rekotlin.Action
import java.math.BigDecimal
data class SaltPayBalanceWidgetData(
val state: ProgressState? = null,
val currencySymbol: String? = null,
val currency: String? = null,
val fiatAmount: BigDecimal? = null,
val fiatCurrency: FiatCurrency? = null,
)
class SaltPayBalanceWidget(
private val binding: LayoutSingleWalletBalanceBinding,
private val data: SaltPayBalanceWidgetData,
) {
fun setup(): Unit = with(binding) {
if (data.state == ProgressState.Loading) {
veilBalance.veil()
veilBalanceCrypto.veil()
} else {
// veilBalance.unVeil()
veilBalanceCrypto.unVeil()
}
tvProcessing.animateVisibility(
show = data.state == ProgressState.Error,
)
veilBalanceCrypto.animateVisibility(
show = data.state != ProgressState.Error,
)
if (data.fiatAmount == null) {
//TODO: SaltPay: A tricky solution to the problem with displaying rates
// If the rates are loaded after the walletManager.update() is completely updated,
// then this problem can be avoided
actionDebouncer(WalletAction.LoadFiatRate())
} else {
veilBalance.unVeil()
tvBalance.text = data.fiatAmount?.formatAmountAsSpannedString(
currencySymbol = data.fiatCurrency?.symbol ?: "",
)
}
tvBalanceCrypto.text = data.currency
tvCurrencyName.text = data.fiatCurrency?.code
tvCurrencyName.setOnClickListener {
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
}
}
}
private val actionDebouncer = debounce<Action>(500, mainScope) { store.dispatch(it) }

View file

@ -1,55 +0,0 @@
package com.tangem.tap.features.wallet.ui.wallet
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.ui.TokenData
import com.tangem.tap.features.wallet.ui.WalletFragment
import com.tangem.tap.store
import com.tangem.wallet.databinding.FragmentWalletBinding
import timber.log.Timber
class SaltPaySingleWalletView : WalletView() {
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
setFragment(fragment, binding)
onViewCreated()
showSingleWalletView(binding)
}
private fun showSingleWalletView(binding: FragmentWalletBinding) = with(binding) {
rvMultiwallet.hide()
btnAddToken.hide()
rowButtons.hide()
rvPendingTransaction.hide()
tvTwinCardNumber.hide()
pbLoadingUserTokens.hide()
lCardBalance.root.hide()
lAddress.root.hide()
lSingleWalletBalance.root.show()
}
override fun onViewCreated() {
}
override fun onNewState(state: WalletState) {
val binding = binding ?: return
val tokenData = state.primaryWallet?.currencyData?.token ?: return
setupBalance(state, tokenData, binding)
}
private fun setupBalance(state: WalletState, tokenData: TokenData, binding: FragmentWalletBinding) {
binding.lSingleWalletBalance.root.show()
Timber.e("Current address is ${state.primaryWalletManager?.wallet?.address}")
SaltPayBalanceWidget(
binding = binding.lSingleWalletBalance,
data = SaltPayBalanceWidgetData(
state = state.state,
currencySymbol = tokenData.tokenSymbol,
currency = tokenData.amountFormatted,
fiatAmount = tokenData.fiatAmount, // TODO: show fiatAmount
fiatCurrency = store.state.globalState.appCurrency,
),
).setup()
}
}

View file

@ -0,0 +1,88 @@
package com.tangem.tap.features.wallet.ui.wallet
import com.tangem.domain.common.extensions.debounce
import com.tangem.tap.common.extensions.animateVisibility
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
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.WalletFragment
import com.tangem.tap.mainScope
import com.tangem.tap.store
import com.tangem.wallet.databinding.FragmentWalletBinding
import com.tangem.wallet.databinding.LayoutSaltPayWalletBinding
import org.rekotlin.Action
class SaltPayWalletView : WalletView() {
private lateinit var saltPayBinding: LayoutSaltPayWalletBinding
private val actionDebouncer = debounce<Action>(500, mainScope) { store.dispatch(it) }
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
saltPayBinding = binding.lSaltPayWallet
setFragment(fragment, binding)
onViewCreated()
showSaltPayView(binding)
}
private fun showSaltPayView(binding: FragmentWalletBinding) = with(binding) {
rvWarningMessages.hide()
rvPendingTransaction.hide()
rvMultiwallet.hide()
tvTwinCardNumber.hide()
lCardBalance.root.hide()
lSingleWalletBalance.root.hide()
lAddress.root.hide()
rowButtons.hide()
btnAddToken.hide()
pbLoadingUserTokens.hide()
lSaltPayWallet.root.show()
}
override fun onViewCreated() {
}
override fun onNewState(state: WalletState) {
setupBalanceWidget(state)
}
private fun setupBalanceWidget(state: WalletState) = with(saltPayBinding.lSaltPayBalance) {
val tokenData = state.primaryTokenData ?: return@with
val appCurrency = store.state.globalState.appCurrency
val mainProgressState = state.state
if (mainProgressState == ProgressState.Loading) {
veilBalance.veil()
veilBalanceCrypto.veil()
} else {
veilBalanceCrypto.unVeil()
}
tvProcessing.animateVisibility(show = mainProgressState == ProgressState.Error)
veilBalanceCrypto.animateVisibility(show = mainProgressState != ProgressState.Error)
if (tokenData.currencyData.fiatAmount == null) {
actionDebouncer(WalletAction.LoadFiatRate())
} else {
veilBalance.unVeil()
tvBalance.text = tokenData.currencyData.fiatAmount.formatAmountAsSpannedString(
currencySymbol = appCurrency.symbol,
)
}
tvBalanceCrypto.text = tokenData.currencyData.amountFormatted
tvCurrencyName.text = appCurrency.code
tvCurrencyName.setOnClickListener {
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
}
btnBuy.show(tokenData.isAvailableToBuy)
btnBuy.setOnClickListener {
store.dispatch(WalletAction.TradeCryptoAction.Buy(false))
}
}
}

View file

@ -35,6 +35,7 @@ class SingleWalletView : WalletView() {
}
private fun showSingleWalletView(binding: FragmentWalletBinding) = with(binding) {
lSaltPayWallet.root.hide()
tvTwinCardNumber.hide()
rvMultiwallet.hide()
btnAddToken.hide()
@ -63,13 +64,13 @@ class SingleWalletView : WalletView() {
override fun onNewState(state: WalletState) {
val binding = binding ?: return
state.primaryWallet ?: return
val primaryWalletData = state.primaryWalletData ?: return
setupTwinCards(state.twinCardsState, binding)
setupButtons(state.primaryWallet, binding, state.isExchangeServiceFeatureOn)
setupButtons(primaryWalletData, binding, state.isExchangeServiceFeatureOn)
setupAddressCard(state, binding)
showPendingTransactionsIfPresent(state.primaryWallet.pendingTransactions)
setupBalance(state, state.primaryWallet)
showPendingTransactionsIfPresent(primaryWalletData.pendingTransactions)
setupBalance(state, primaryWalletData)
}
private fun showPendingTransactionsIfPresent(pendingTransactions: List<PendingTransaction>) {
@ -88,6 +89,7 @@ class SingleWalletView : WalletView() {
binding = this.lCardBalance,
fragment = fragment,
data = primaryWallet.currencyData,
token = state.primaryTokenData?.currencyData,
isTwinCard = state.isTangemTwins,
).setup()
}
@ -152,7 +154,7 @@ class SingleWalletView : WalletView() {
}
private fun setupAddressCard(state: WalletState, binding: FragmentWalletBinding) = with(binding.lAddress) {
val primaryWallet = state.primaryWallet
val primaryWallet = state.primaryWalletData
if (primaryWallet?.walletAddresses != null && primaryWallet.currency is Currency.Blockchain) {
binding.lAddress.root.show()
if (primaryWallet.shouldShowMultipleAddress()) {
@ -187,7 +189,7 @@ class SingleWalletView : WalletView() {
private fun setupCardInfo(state: WalletState) {
val textView = binding?.lAddress?.tvInfo
val blockchain = state.primaryWallet?.currency?.blockchain
val blockchain = state.primaryWalletData?.currency?.blockchain
if (textView != null && blockchain != null) {
textView.text = textView.getString(
id = R.string.address_qr_code_message_format,

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/button_disabled" android:state_enabled="false" />
<item android:color="@color/button_secondary" />
</selector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#66FFFFFF" android:state_enabled="false" />
<item android:color="@color/text_primary_1" />
</selector>

View file

@ -177,6 +177,15 @@
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />
<include
android:id="@+id/l_salt_pay_wallet"
layout="@layout/layout_salt_pay_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />
<include
android:id="@+id/l_address"
layout="@layout/layout_address"

View file

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/card_balance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="12dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@string/onboarding_balance_title"
android:textColor="@color/text_tertiary"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/tv_currency_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.skydoves.androidveil.VeilLayout
android:id="@+id/veil_balance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@id/tv_processing"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:veilLayout_baseColor="@color/lightGray0"
app:veilLayout_highlightColor="@color/lightGray1"
app:veilLayout_layout="@layout/card_total_balance_shimmer"
app:veilLayout_radius="4dp"
app:veilLayout_shimmerEnable="true"
app:veilLayout_veiled="true"
tools:veilLayout_veiled="false"
tools:visibility="visible">
<TextView
android:id="@+id/tv_balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:minWidth="152dp"
android:textColor="@color/text_primary_1"
android:textSize="24sp"
android:textStyle="bold"
tools:text="22 325.40 $" />
</com.skydoves.androidveil.VeilLayout>
<com.skydoves.androidveil.VeilLayout
android:id="@+id/veil_balance_crypto"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/veil_balance"
app:veilLayout_baseColor="@color/lightGray0"
app:veilLayout_highlightColor="@color/lightGray1"
app:veilLayout_layout="@layout/card_total_balance_shimmer"
app:veilLayout_radius="4dp"
app:veilLayout_shimmerEnable="true"
app:veilLayout_veiled="true"
tools:veilLayout_veiled="false"
tools:visibility="visible">
<TextView
android:id="@+id/tv_balance_crypto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="2dp"
android:maxLines="1"
android:minWidth="152dp"
android:textColor="@color/text_tertiary"
android:textSize="12sp"
tools:text="5.13123123123 ETH"
tools:visibility="visible" />
</com.skydoves.androidveil.VeilLayout>
<TextView
android:id="@+id/tv_processing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="@string/wallet_balance_blockchain_unreachable"
android:textColor="@color/warning"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/veil_balance" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_buy"
style="@style/BaseSaltPayButton"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="12dp"
android:text="@string/wallet_button_buy"
android:visibility="gone"
app:icon="@drawable/ic_add"
app:iconGravity="textStart"
app:iconTint="@color/selector_saltpay_btn_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/veil_balance_crypto"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_currency_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textColor="@color/text_tertiary"
android:textSize="14sp"
android:textStyle="bold"
app:drawableEndCompat="@drawable/ic_arrow_angle_down"
app:drawableTint="@color/text_tertiary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="USD" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cl_salt_pay_wallet_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingTop="6dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp">
<include
android:id="@+id/l_salt_pay_balance"
layout="@layout/layout_salt_pay_balance"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -131,6 +131,19 @@
<item name="android:lineSpacingExtra">4sp</item>
</style>
<style name="BaseSaltPayButton">
<item name="android:minHeight">40dp</item>
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
<item name="android:elevation">0dp</item>
<item name="android:textColor">@color/selector_saltpay_btn_text</item>
<item name="android:textAllCaps">false</item>
<item name="android:letterSpacing">0</item>
<item name="android:backgroundTint">@color/selector_saltpay_btn</item>
<item name="cornerRadius">@dimen/btn_corner_radius_medium</item>
<item name="android:stateListAnimator">@null</item>
</style>
<style name="heading">
<item name="android:textSize">24sp</item>
<item name="android:textColor">#060606</item>