Updated on 2026-08-14

This commit is contained in:
Tangem 2021-11-03 13:36:26 +00:00
commit fb3d9cd2d6
20 changed files with 220 additions and 181 deletions

View file

@ -157,22 +157,22 @@ class TapWalletManager {
private fun loadMultiWalletData(
card: Card, primaryBlockchain: Blockchain?, primaryWalletManager: WalletManager?
) {
val primaryTokens = primaryWalletManager?.cardTokens ?: emptySet()
val primaryTokens = primaryWalletManager?.cardTokens?.toList() ?: emptyList()
val savedCurrencies = currenciesRepository.loadCardCurrencies(card.cardId)
if (savedCurrencies == null) {
if (primaryBlockchain != null && primaryWalletManager != null) {
store.dispatch(WalletAction.MultiWallet.SaveCurrencies(
CardCurrencies(
blockchains = setOf(primaryBlockchain), tokens = primaryTokens
blockchains = listOf(primaryBlockchain), tokens = primaryTokens
)))
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager))
store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(primaryBlockchain)))
store.dispatch(WalletAction.MultiWallet.AddTokens(primaryTokens.toList()))
} else {
val blockchains = setOf(Blockchain.Bitcoin, Blockchain.Ethereum)
val blockchains = listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
store.dispatch(WalletAction.MultiWallet.SaveCurrencies(
CardCurrencies(blockchains = blockchains, tokens = emptySet())
CardCurrencies(blockchains = blockchains, tokens = emptyList())
))
val walletManagers =
walletManagerFactory.makeWalletManagersForApp(card, blockchains.toList())

View file

@ -14,14 +14,14 @@ import com.tangem.tap.network.createMoshi
class CurrenciesRepository(val context: Application) {
private val moshi = createMoshi()
private val blockchainsAdapter: JsonAdapter<Set<Blockchain>> = moshi.adapter(
Types.newParameterizedType(Set::class.java, Blockchain::class.java)
private val blockchainsAdapter: JsonAdapter<List<Blockchain>> = moshi.adapter(
Types.newParameterizedType(List::class.java, Blockchain::class.java)
)
private val tokensAdapter: JsonAdapter<Set<TokenDao>> = moshi.adapter(
Types.newParameterizedType(Set::class.java, TokenDao::class.java)
private val tokensAdapter: JsonAdapter<List<TokenDao>> = moshi.adapter(
Types.newParameterizedType(List::class.java, TokenDao::class.java)
)
private val obsoleteTokensAdapter: JsonAdapter<Set<ObsoleteTokenDao>> = moshi.adapter(
Types.newParameterizedType(Set::class.java, ObsoleteTokenDao::class.java)
private val obsoleteTokensAdapter: JsonAdapter<List<ObsoleteTokenDao>> = moshi.adapter(
Types.newParameterizedType(List::class.java, ObsoleteTokenDao::class.java)
)
fun loadCardCurrencies(cardId: String): CardCurrencies? {
@ -51,48 +51,48 @@ class CurrenciesRepository(val context: Application) {
}
fun removeToken(cardId: String, token: Token) {
val tokens = loadSavedTokens(cardId).filterNot { it == token }.toSet()
val tokens = loadSavedTokens(cardId).filterNot { it == token }
saveTokens(cardId, tokens)
}
fun removeBlockchain(cardId: String, blockchain: Blockchain) {
val blockchains = loadSavedBlockchains(cardId).filterNot { it == blockchain }.toSet()
val blockchains = loadSavedBlockchains(cardId).filterNot { it == blockchain }
saveBlockchains(cardId, blockchains)
}
private fun loadSavedTokens(cardId: String): Set<Token> {
private fun loadSavedTokens(cardId: String): List<Token> {
val json = try {
context.readFileText(getFileNameForTokens(cardId))
} catch (exception: Exception) {
return emptySet()
return emptyList()
}
return try {
tokensAdapter.fromJson(json)!!.map { it.toToken() }.toSet()
tokensAdapter.fromJson(json)!!.map { it.toToken() }
} catch (exception: Exception) {
try {
obsoleteTokensAdapter.fromJson(json)!!.map { it.toToken() }.toSet()
obsoleteTokensAdapter.fromJson(json)!!.map { it.toToken() }
} catch (exception: Exception) {
emptySet()
emptyList()
}
}
}
private fun saveTokens(cardId: String, tokens: Set<Token>) {
val json = tokensAdapter.toJson(tokens.map { TokenDao.fromToken(it) }.toSet())
private fun saveTokens(cardId: String, tokens: List<Token>) {
val json = tokensAdapter.toJson(tokens.map { TokenDao.fromToken(it) }.distinct())
context.rewriteFile(json, getFileNameForTokens(cardId))
}
private fun loadSavedBlockchains(cardId: String): Set<Blockchain> {
private fun loadSavedBlockchains(cardId: String): List<Blockchain> {
return try {
val json = context.readFileText(getFileNameForBlockchains(cardId))
blockchainsAdapter.fromJson(json) ?: emptySet()
blockchainsAdapter.fromJson(json) ?: emptyList()
} catch (exception: Exception) {
emptySet()
emptyList()
}
}
private fun saveBlockchains(cardId: String, blockchains: Set<Blockchain>) {
private fun saveBlockchains(cardId: String, blockchains: List<Blockchain>) {
val json = blockchainsAdapter.toJson(blockchains)
context.rewriteFile(json, getFileNameForBlockchains(cardId))
}
@ -224,12 +224,12 @@ data class ObsoleteTokenDao(
@JsonClass(generateAdapter = true)
data class CardCurrenciesDao(
val tokens: Set<TokenDao>,
val blockchains: Set<Blockchain>,
val tokens: List<TokenDao>,
val blockchains: List<Blockchain>,
) {
fun toCardCurrencies(): CardCurrencies {
return CardCurrencies(
tokens = tokens.map { it.toToken() }.toSet(),
tokens = tokens.map { it.toToken() }.distinct(),
blockchains = blockchains
)
}
@ -237,7 +237,7 @@ data class CardCurrenciesDao(
companion object {
fun fromCardCurrencies(cardCurrencies: CardCurrencies): CardCurrenciesDao {
return CardCurrenciesDao(
tokens = cardCurrencies.tokens.map { TokenDao.fromToken(it) }.toSet(),
tokens = cardCurrencies.tokens.map { TokenDao.fromToken(it) }.distinct(),
blockchains = cardCurrencies.blockchains
)
}
@ -245,6 +245,6 @@ data class CardCurrenciesDao(
}
data class CardCurrencies(
val tokens: Set<Token>,
val blockchains: Set<Blockchain>,
val tokens: List<Token>,
val blockchains: List<Blockchain>,
)

View file

@ -10,6 +10,7 @@ import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.isMultiwalletAllowed
import com.tangem.tap.domain.twins.getTwinCardIdForUser
import com.tangem.tap.features.details.redux.DetailsAction
import com.tangem.tap.features.details.redux.DetailsState
@ -112,6 +113,7 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
store.dispatch(GlobalAction.SendFeedback(FeedbackEmail()))
}
tv_wallet_connect.show(state.card?.isMultiwalletAllowed == true)
tv_wallet_connect.setOnClickListener {
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
}

View file

@ -68,9 +68,9 @@ class AmountMiddleware {
} else {
val amountErrors = extractErrorsForAmountField(transactionErrors)
if (amountErrors.isNotEmpty()) {
transactionErrors.removeAll(amountErrors)
dispatch(AmountAction.SetAmountError(createValidateTransactionError(amountErrors, walletManager)))
}
transactionErrors.removeAll(amountErrors)
if (transactionErrors.isNotEmpty()) {
dispatch(SendAction.SendError(createValidateTransactionError(transactionErrors, walletManager)))
}
@ -84,7 +84,7 @@ class AmountMiddleware {
dispatch(AmountAction.SetAmount(sendState.amountState.balanceCrypto, false))
if (sendState.amountState.isCoinAmount()) {
dispatch(FeeAction.ChangeLayoutVisibility(main = true, controls = true, chipGroup = true))
dispatch(FeeAction.ChangeLayoutVisibility(main = true, controls = true))
dispatch(FeeActionUi.ChangeIncludeFee(true))
}

View file

@ -29,7 +29,7 @@ class RequestFeeMiddleware {
if (!SendState.isReadyToRequestFee()) {
dispatch(FeeAction.FeeCalculation.SetFeeError(FeeAction.Error.ADDRESS_OR_AMOUNT_IS_EMPTY))
dispatch(FeeAction.ChangeLayoutVisibility(main = false, chipGroup = true))
// dispatch(FeeAction.ChangeLayoutVisibility(main = false, chipGroup = true))
dispatch(ReceiptAction.RefreshReceipt)
dispatch(SendAction.ChangeSendButtonState(sendState.getButtonState()))
return
@ -60,7 +60,7 @@ class RequestFeeMiddleware {
}
is Result.Failure -> {
dispatch(FeeAction.FeeCalculation.SetFeeError(FeeAction.Error.REQUEST_FAILED))
dispatch(FeeAction.ChangeLayoutVisibility(main = false, controls = false, chipGroup = false))
dispatch(FeeAction.ChangeLayoutVisibility(main = false))
}
}
dispatch(AmountActionUi.CheckAmountToSend)

View file

@ -254,7 +254,7 @@ fun extractErrorsForAmountField(errors: EnumSet<TransactionError>): EnumSet<Tran
showIntoAmountField.add(it)
}
TransactionError.TotalExceedsBalance -> {
val notAcceptable = listOf(TransactionError.FeeExceedsBalance, TransactionError.FeeExceedsBalance)
val notAcceptable = listOf(TransactionError.AmountExceedsBalance, TransactionError.FeeExceedsBalance)
if (!showIntoAmountField.containsAll(notAcceptable)) showIntoAmountField.add(it)
}
TransactionError.InvalidAmountValue -> showIntoAmountField.add(it)

View file

@ -45,7 +45,7 @@ class FeeReducer : SendInternalReducer {
state.copy(
mainLayoutIsVisible = getVisibility(state.mainLayoutIsVisible, action.main),
controlsLayoutIsVisible = getVisibility(state.controlsLayoutIsVisible, action.controls),
feeChipGroupIsVisible = getVisibility(state.mainLayoutIsVisible, action.chipGroup)
feeChipGroupIsVisible = getVisibility(state.feeChipGroupIsVisible, action.chipGroup)
)
}
is FeeAction.FeeCalculation.SetFeeResult -> {

View file

@ -33,7 +33,7 @@ private fun internalReduce(action: Action, state: AppState): TokensState {
}
private fun List<WalletData>.toCardCurrencies(): CardCurrencies {
val tokens = mapNotNull { (it.currency as? Currency.Token)?.token }.toSet()
val blockchains = mapNotNull { (it.currency as? Currency.Blockchain)?.blockchain }.toSet()
val tokens = mapNotNull { (it.currency as? Currency.Token)?.token }.distinct()
val blockchains = mapNotNull { (it.currency as? Currency.Blockchain)?.blockchain }.distinct()
return CardCurrencies(tokens = tokens, blockchains = blockchains)
}

View file

@ -132,12 +132,31 @@ data class WalletState(
fun replaceWalletInWallets(walletData: WalletData?): List<WalletData> {
if (walletData == null) return wallets
return wallets.filter { it.currencyData.currency != walletData.currencyData.currency } + walletData
var changed = false
val updatedWallets = wallets.map {
if (it.currencyData.currency == walletData.currencyData.currency) {
changed = true
walletData
} else {
it
}
}
return if (changed) updatedWallets else wallets + walletData
}
fun replaceSomeWallets(newWallets: List<WalletData>): List<WalletData> {
val currencies = newWallets.map { it.currencyData.currency }
return wallets.filter { !currencies.contains(it.currencyData.currency) } + newWallets
val remainingWallets: MutableList<WalletData> = newWallets.toMutableList()
val updatedWallets = wallets.map { wallet ->
val newWallet = newWallets
.firstOrNull { wallet.currencyData.currency == it.currencyData.currency }
if (newWallet == null) {
wallet
} else {
remainingWallets.remove(newWallet)
newWallet
}
}
return updatedWallets + remainingWallets
}
fun addWalletManagers(newWalletManagers: List<WalletManager>): WalletState {

View file

@ -84,7 +84,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
btn_share.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) }
btn_top_up.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Buy) }
btn_trade.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Buy) }
btn_sell.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Sell) }
}
@ -138,7 +138,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
srl_wallet_details.isRefreshing = false
}
btn_top_up.isEnabled = selectedWallet.tradeCryptoState.buyingAllowed
btn_trade.isEnabled = selectedWallet.tradeCryptoState.buyingAllowed
btn_sell.show(selectedWallet.tradeCryptoState.sellingAllowed)
}
@ -286,7 +286,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.meny_remove -> {
R.id.menu_remove -> {
store.state.walletState.getSelectedWalletData()?.let { walletData ->
store.dispatch(WalletAction.MultiWallet.RemoveWallet(walletData))
store.dispatch(WalletAction.MultiWallet.SelectWallet(null))
@ -300,9 +300,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
if (store.state.walletState.canBeRemoved(store.state.walletState.getSelectedWalletData())) {
inflater.inflate(R.menu.wallet_details, menu)
}
inflater.inflate(R.menu.wallet_details, menu)
val walletCanBeRemoved = store.state.walletState.canBeRemoved(
store.state.walletState.getSelectedWalletData()
)
menu.getItem(0).isEnabled = walletCanBeRemoved
}
}

View file

@ -18,7 +18,6 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.item_currency_wallet.view.*
import java.math.BigDecimal
class WalletAdapter
: ListAdapter<WalletData, WalletAdapter.WalletsViewHolder>(DiffUtilCallback) {
@ -28,36 +27,8 @@ class WalletAdapter
}
fun submitList(list: List<WalletData>, primaryBlockchain: Blockchain?, primaryToken: Token? = null) {
val listModified = list.toMutableList()
val primaryBlockchainWallet = when (
val index = listModified.indexOfFirst {
(it.currency as? Currency.Blockchain)?.blockchain == primaryBlockchain
}
) {
-1 -> null
else -> listModified.removeAt(index)
}
val primaryTokenWallet = if (primaryToken == null) null else when (
val index = listModified.indexOfFirst { (it.currency as? Currency.Token)?.token == primaryToken }
) {
-1 -> null
else -> listModified.removeAt(index)
}
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.fiatAmount ?: BigDecimal.ZERO }
.thenBy { it.currencyData.currency }
)
val sortedList = listOfNotNull(primaryBlockchainWallet, primaryTokenWallet) + sorted
super.submitList(sortedList)
// We used this method to sort the list of currencies. Sorting is disabled for now.
super.submitList(list)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WalletsViewHolder {

View file

@ -142,12 +142,10 @@ class SingleWalletView : WalletView {
}
btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) }
btn_top_up.setOnClickListener {
tradeCryptoAction(state.tradeCryptoState)
}
setupTradeButton(fragment, state.tradeCryptoState)
}
private fun tradeCryptoAction(tradeCryptoState: TradeCryptoState) {
private fun setupTradeButton(fragment: WalletFragment, tradeCryptoState: TradeCryptoState) {
val allowedToBuy = tradeCryptoState.buyingAllowed
val allowedToSell = tradeCryptoState.sellingAllowed
val action = when {
@ -156,7 +154,23 @@ class SingleWalletView : WalletView {
allowedToBuy && allowedToSell -> WalletAction.ShowDialog.ChooseTradeActionDialog
else -> null
}
if (action != null) store.dispatch(action)
val text = when {
allowedToBuy && !allowedToSell -> R.string.wallet_button_buy
!allowedToBuy && allowedToSell -> R.string.wallet_button_sell
allowedToBuy && allowedToSell -> R.string.wallet_button_trade
else -> R.string.wallet_button_trade
}
val icon = when {
allowedToBuy && !allowedToSell -> R.drawable.ic_arrow_up_short_btn
!allowedToBuy && allowedToSell -> R.drawable.ic_arrow_down_short_button
allowedToBuy && allowedToSell -> R.drawable.ic_arrows_up_down_short_btn
else -> R.string.wallet_button_trade
}
with(fragment) {
btn_trade.text = getText(text)
btn_trade.setCompoundDrawablesWithIntrinsicBounds(0, icon, 0, 0)
btn_trade.setOnClickListener { if (action != null) store.dispatch(action) }
}
}
private fun setupButtonsType(state: WalletData, fragment: WalletFragment) = with(fragment) {

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:state_enabled="true" android:alpha="@dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
</selector>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="20">
<group>
<path
android:pathData="M5.853,11.6645L9.7814,8.075C10.0495,7.8439 10.0734,7.3871 9.84,7.1191C9.6067,6.8511 9.1615,6.824 8.9084,7.0724L6.0712,9.6665L6.0712,0.8398C6.0712,0.468 5.7781,0.1667 5.4165,0.1667C5.0549,0.1667 4.7618,0.468 4.7618,0.8398L4.7618,9.6665L1.9246,7.0724C1.6715,6.824 1.2271,6.8576 0.9937,7.1256C0.7604,7.3936 0.7835,7.8439 1.0516,8.075L4.98,11.6645C5.2976,11.8989 5.5827,11.8802 5.853,11.6645L5.853,11.6645Z"
android:fillColor="#ffffff"/>
</group>
</vector>

View file

@ -43,27 +43,46 @@
android:layout_marginEnd="16dp"
android:layout_marginBottom="33dp">
<TextView
android:id="@+id/tv_card_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:text="@string/details_section_title_card"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/separatorGrey2"
app:layout_constraintTop_toBottomOf="@id/tv_card_title" />
<TextView
android:id="@+id/tv_card_id_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_cid"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@id/tv_card_title" />
<TextView
android:id="@+id/tv_card_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_title"
tools:text="0000 0000 0000 0000" />
<TextView
@ -115,33 +134,47 @@
tools:text="48 hashes" />
<TextView
android:id="@+id/tv_disclaimer"
android:id="@+id/tv_security"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes_title"
tools:text="Long Tap" />
<TextView
android:id="@+id/tv_security_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_manage_security"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes" />
<TextView
android:id="@+id/tv_erase_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/disclaimer_title"
android:text="@string/details_row_title_erase_wallet"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes_title" />
<TextView
android:id="@+id/tv_card_tou"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="10dp"
android:text="@string/details_row_title_card_tou"
android:textColor="@color/darkGray6"
android:textSize="16sp"
android:visibility="gone"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_disclaimer" />
app:layout_constraintTop_toBottomOf="@id/tv_security_title" />
<TextView
android:id="@+id/tv_settings_title"
@ -149,12 +182,12 @@
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:paddingBottom="4dp"
android:text="@string/details_section_title_settings"
android:text="@string/details_section_title_app"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_tou" />
app:layout_constraintTop_toBottomOf="@id/tv_erase_wallet" />
<View
android:layout_width="match_parent"
@ -162,6 +195,7 @@
android:background="@color/separatorGrey2"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
<TextView
android:id="@+id/tv_app_currency"
android:layout_width="wrap_content"
@ -171,6 +205,7 @@
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title"
tools:text="USD" />
@ -187,6 +222,37 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
<TextView
android:id="@+id/tv_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/disclaimer_title"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_app_currency_title" />
<TextView
android:id="@+id/tv_card_tou"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="10dp"
android:text="@string/details_row_title_card_tou"
android:textColor="@color/darkGray6"
android:textSize="16sp"
android:visibility="gone"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_disclaimer" />
<TextView
android:id="@+id/tv_send_feedback"
android:layout_width="match_parent"
@ -197,8 +263,9 @@
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_app_currency_title" />
app:layout_constraintTop_toBottomOf="@id/tv_card_tou" />
<TextView
android:id="@+id/tv_wallet_connect"
@ -210,76 +277,10 @@
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:drawableTint="@color/darkGray1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_send_feedback" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="tv_wallet_connect,tv_send_feedback" />
<TextView
android:id="@+id/tv_card_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:paddingBottom="4dp"
android:text="@string/details_section_title_card"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/separatorGrey2"
app:layout_constraintTop_toBottomOf="@id/tv_card_title" />
<TextView
android:id="@+id/tv_security"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textColor="@color/darkGray1"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_title"
tools:text="Long Tap" />
<TextView
android:id="@+id/tv_security_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_manage_security"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_card_title" />
<TextView
android:id="@+id/tv_erase_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:text="@string/details_row_title_erase_wallet"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_security_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View file

@ -23,6 +23,7 @@
android:layout_height="?attr/actionBarSize"
app:menu="@menu/wallet_details"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
android:theme="@style/ThemeOverlay.MyTheme.Toolbar"
app:title=" " />
</com.google.android.material.appbar.AppBarLayout>
@ -131,7 +132,7 @@
app:constraint_referenced_ids="l_wallet_details,card_pending_transaction_warning" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_top_up"
android:id="@+id/btn_trade"
style="@style/TapButtonWithIcon"
android:layout_width="0dp"
android:layout_marginStart="16dp"
@ -151,7 +152,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="btn_top_up, btn_sell" />
app:constraint_referenced_ids="btn_trade, btn_sell" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_right_button"
@ -172,7 +173,7 @@
app:icon="@drawable/ic_arrow_down"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/btn_top_up"
app:layout_constraintStart_toEndOf="@id/btn_trade"
app:layout_constraintEnd_toStartOf="@id/btn_confirm"
app:layout_constraintTop_toBottomOf="@id/barrier"
app:layout_constraintVertical_bias="1" />

View file

@ -9,6 +9,7 @@
android:id="@+id/btn_scan_short"
style="@style/TapBlackButton"
android:layout_width="0dp"
android:layout_height="52dp"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:layout_marginBottom="33dp"
@ -17,14 +18,15 @@
android:paddingTop="7dp"
android:text="@string/wallet_button_scan"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btn_top_up"
app:layout_constraintEnd_toStartOf="@id/btn_trade"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_top_up"
android:id="@+id/btn_trade"
style="@style/TapButton"
android:layout_width="0dp"
android:layout_height="52dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:layout_marginBottom="33dp"
@ -42,6 +44,7 @@
android:id="@+id/btn_confirm_short"
style="@style/TapButton"
android:layout_width="0dp"
android:layout_height="52dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
@ -52,7 +55,7 @@
android:text="@string/wallet_button_send"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/btn_top_up"
app:layout_constraintStart_toEndOf="@+id/btn_trade"
app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -2,7 +2,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/meny_remove"
android:title="@string/common_remove"
android:id="@+id/menu_remove"
android:title="@string/remove_token"
app:showAsAction="always" />
</menu>

View file

@ -89,6 +89,7 @@
<string name="custom_token_name_input_placeholder" translatable="false">ex. USD Coin</string>
<string name="custom_token_token_symbol_input_placeholder" translatable="false">ex. USDC</string>
<string name="add_token_added" translatable="false">Added</string>
<string name="remove_token" translatable="false">Remove token</string>
//Details
<string name="details_section_title_blockchain" translatable="false">Blockchain</string>

View file

@ -20,6 +20,14 @@
<item name="actionMenuTextColor">@android:color/white</item>
</style>
<!-- Toolbar - overrides the menu text color to use a selector that responds to whether it's enabled or not -->
<style name="ThemeOverlay.MyTheme.Toolbar" parent="ThemeOverlay.MaterialComponents.Toolbar.Surface">
<!-- Color used in the icons of menu actions (i.e. non-overflow menu items). This is just convention, this will affect anything that uses ?attr/colorControlNormal) -->
<item name="colorControlNormal">@color/menu_item_color</item>
<!-- Color used in the text of menu actions (i.e. non-overflow menu items) -->
<item name="actionMenuTextColor">@color/menu_item_color</item>
</style>
<!-- EditText -->
<style name="StyledEditText" parent="TextAppearance.MaterialComponents.Body1">
<item name="colorControlNormal">#e34b1c</item>