Updated on 2026-08-14

This commit is contained in:
Tangem 2021-05-14 15:50:59 +03:00
commit a42729b839
24 changed files with 336 additions and 105 deletions

3
.gitignore vendored
View file

@ -6,6 +6,9 @@
# Local configuration file (sdk path, etc)
local.properties
# Google services
# Gradle generated files
.gradle

View file

@ -75,13 +75,9 @@ dependencies {
implementation 'com.google.android.play:core-ktx:1.8.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
// TODO: change to prod dependencies when they are available
// implementation 'com.tangem:blockchain:1.164.0'
// implementation 'com.tangem:core:1.109.0'
// implementation 'com.tangem:sdk:1.109.0'
implementation 'blockchain-sdk-kotlin:blockchain:tangem-20210416.151414-8'
implementation 'com.tangem:tangem-core:tangem-20210414.185224-2'
implementation 'com.tangem:tangem-sdk:tangem-20210414.185231-2'
implementation 'com.tangem:blockchain:develop-5'
implementation 'com.tangem:core:develop-10'
implementation 'com.tangem:sdk:develop-10'
// WebView
implementation "androidx.browser:browser:1.3.0"

View file

@ -629,6 +629,13 @@
"name" : "QASH",
"contractAddress" : "0x618e75ac90b12c6049ba3b27f5d5f8651b0037f6"
},
{
"decimalCount" : 8,
"symbol" : "QCX",
"name" : "QuickX Protocol",
"contractAddress" : "0xf9e5af7b42d31d51677c75bbbd37c1986ec79aee",
"customIcon": "qcx"
},
{
"decimalCount" : 8,
"symbol" : "QRL",

View file

@ -0,0 +1,86 @@
package com.tangem.tap.common.extensions
import android.widget.ImageView
import android.widget.TextView
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.wallet.R
fun Picasso.loadCurrenciesIcon(
imageView: ImageView,
textView: TextView,
token: Token? = null,
blockchain: Blockchain?,
) {
val blockchain = blockchain ?: Blockchain.Ethereum
val url = if (token != null) {
IconsUtil.getTokenIconUri(blockchain, token)
} else {
IconsUtil.getBlockchainIconUri(blockchain)
}
imageView.setImageDrawable(null)
imageView.colorFilter = null
textView.text = null
when {
url != null -> {
this.load(url)
.placeholder(R.drawable.shape_circle)
?.into(imageView,
object : Callback {
override fun onError(e: Exception?) {
setOfflineCurrencyImage(imageView, textView, token, blockchain)
}
override fun onSuccess() {
}
})
}
token?.symbol == QCX -> {
this.load(R.drawable.ic_qcx)?.into(imageView)
}
else -> {
setOfflineCurrencyImage(imageView, textView, token, blockchain)
}
}
}
private const val QCX = "QCX"
private fun setOfflineCurrencyImage(
imageView: ImageView,
textView: TextView,
token: Token?,
blockchain: Blockchain,
) {
if (token != null) {
setTokenImage(imageView, textView, token)
} else {
setBlockchainImage(imageView, textView, blockchain)
}
}
private fun setBlockchainImage(
imageView: ImageView,
textView: TextView,
blockchain: Blockchain
) {
imageView.setImageResource(blockchain.getIconRes())
imageView.colorFilter = null
textView.text = null
}
private fun setTokenImage(
imageView: ImageView,
textView: TextView,
token: Token
) {
imageView.setImageResource(R.drawable.shape_circle)
imageView.setColorFilter(token.getColor())
textView.text = token.symbol.take(1)
}

View file

@ -199,13 +199,12 @@ class TapWalletManager {
store.dispatch(WalletAction.MultiWallet.FindBlockchainsInUse(card, walletManagerFactory))
store.dispatch(WalletAction.MultiWallet.FindTokensInUse)
} else {
val blockchains = listOfNotNull(primaryBlockchain) + savedCurrencies.blockchains
val blockchains = savedCurrencies.blockchains
val walletManagers = walletManagerFactory.makeWalletManagersForApp(card, blockchains)
val tokens = presetTokens + savedCurrencies.tokens
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManagers))
store.dispatch(WalletAction.MultiWallet.AddBlockchains(blockchains))
store.dispatch(WalletAction.MultiWallet.AddTokens(tokens))
store.dispatch(WalletAction.MultiWallet.AddTokens(savedCurrencies.tokens))
store.dispatch(WalletAction.MultiWallet.FindTokensInUse)
}
}

View file

@ -1,5 +1,7 @@
package com.tangem.tap.domain.configurable.warningMessage
import android.view.View
import androidx.annotation.StringRes
import com.squareup.moshi.Json
import com.tangem.blockchain.common.Blockchain
@ -7,15 +9,16 @@ import com.tangem.blockchain.common.Blockchain
[REDACTED_AUTHOR]
*/
data class WarningMessage(
val title: String,
val message: String,
val type: Type,
val priority: Priority,
val location: List<Location>,
private val blockchains: List<String>?,
val titleResId: Int? = null,
val messageResId: Int? = null,
val origin: Origin = Origin.Remote,
val title: String,
val message: String,
val type: Type,
val priority: Priority,
val location: List<Location>,
private val blockchains: List<String>?,
@StringRes val titleResId: Int? = null,
@StringRes val messageResId: Int? = null,
val origin: Origin = Origin.Remote,
@StringRes val buttonTextId: Int? = null,
) {
val blockchainList: List<Blockchain>? by lazy {
blockchains?.map { Blockchain.fromId(it.toUpperCase()) }
@ -43,6 +46,7 @@ data class WarningMessage(
Temporary, // можно скрыть (кнопка ОК)
AppRating
}
enum class Location {

View file

@ -3,6 +3,8 @@ package com.tangem.tap.domain.configurable.warningMessage
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
/**
@ -98,6 +100,19 @@ class WarningMessagesManager(
WarningMessage.Origin.Local
)
fun signedHashesMultiWalletWarning(): WarningMessage = WarningMessage(
title = "",
message = "",
type = WarningMessage.Type.Temporary,
priority = WarningMessage.Priority.Info,
location = listOf(WarningMessage.Location.MainScreen),
blockchains = null,
titleResId = R.string.warning_important_security_info,
messageResId = R.string.warning_signed_tx_previously,
origin = WarningMessage.Origin.Local,
buttonTextId = R.string.warning_button_learn_more,
)
fun appRatingWarning(): WarningMessage = WarningMessage(
"",
"",

View file

@ -83,6 +83,7 @@ private fun handleEraseWallet(action: DetailsAction.EraseWallet, state: DetailsS
return when (action) {
DetailsAction.EraseWallet.Check -> {
val notAllowedByCard = state.card?.settingsMask?.contains(Settings.ProhibitPurgeWallet) == true
|| state.card?.settingsMask?.contains(Settings.IsReusable) == false
val notEmpty = state.wallets.any {
!it.recentTransactions.isNullOrEmpty() || it.amounts.toSendableAmounts().isNotEmpty()
}

View file

@ -7,7 +7,10 @@ import androidx.annotation.StringRes
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.*
import com.tangem.tap.common.redux.global.CryptoCurrencyName
@ -16,6 +19,7 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.item_currency_subtitle.view.*
import kotlinx.android.synthetic.main.item_popular_token.view.*
import java.lang.Exception
import java.util.*
class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>(DiffUtilCallback) {
@ -104,9 +108,11 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
view.btn_add_token.show(!isAdded)
view.btn_token_added.show(isAdded)
view.iv_currency.setImageResource(currency.blockchain.getIconRes())
view.iv_currency.colorFilter = null
view.tv_token_letter.text = null
Picasso.get().loadCurrenciesIcon(
imageView = view.iv_currency,
textView = view.tv_token_letter,
blockchain = blockchain, token = null
)
view.btn_add_token.setOnClickListener {
store.dispatch(WalletAction.MultiWallet.AddBlockchain(blockchain))
@ -123,10 +129,11 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
view.btn_add_token.show(!isAdded)
view.btn_token_added.show(isAdded)
view.iv_currency.setImageResource(R.drawable.shape_circle)
view.iv_currency.setColorFilter(token.getColor())
view.tv_token_letter.text = token.symbol.take(1)
Picasso.get().loadCurrenciesIcon(
imageView = view.iv_currency,
textView = view.tv_token_letter,
token = token, blockchain = Blockchain.Ethereum
)
view.btn_add_token.setOnClickListener {
store.dispatch(WalletAction.MultiWallet.AddToken(token))
view.btn_add_token.hide()
@ -152,7 +159,10 @@ sealed class CurrencyListItem {
data class TitleListItem(@StringRes val titleResId: Int) : CurrencyListItem()
companion object {
fun createListOfCurrencies(blockchains: List<Blockchain>, tokens: List<Token>): List<CurrencyListItem> {
fun createListOfCurrencies(
blockchains: List<Blockchain>,
tokens: List<Token>
): List<CurrencyListItem> {
val blockchainsTitle = R.string.add_tokens_subtitle_blockchains
val tokensTitle = R.string.add_tokens_subtitle_tokens
return listOf(TitleListItem(blockchainsTitle)) +

View file

@ -111,6 +111,7 @@ sealed class WalletAction : Action {
object ShowDialog : WalletAction() {
object QrCode : WalletAction()
object ScanFails : WalletAction()
object SignedHashesMultiWalletDialog : WalletAction()
}
object HideDialog : WalletAction()

View file

@ -81,6 +81,9 @@ data class WalletState(
&& (walletData.token == null || walletData.token != store.state.walletState.primaryToken)) {
val walletManager = getWalletManager(walletData.currencyData.currencySymbol)
?: return true
if (walletData.token == null && walletManager.presetTokens.isNotEmpty()) return false
val wallet = walletManager.wallet
if (walletData.blockchain != null) {
return wallet.recentTransactions.toPendingTransactions(wallet.address).isEmpty() &&
@ -112,7 +115,8 @@ sealed class WalletDialog: StateDialog {
) : WalletDialog()
data class SelectAmountToSendDialog(val amounts: List<Amount>?) : WalletDialog()
object ScanFailsDialog: WalletDialog()
object ScanFailsDialog : WalletDialog()
object SignedHashesMultiWalletDialog : WalletDialog()
}
enum class ProgressState { Loading, Done, Error }

View file

@ -39,10 +39,10 @@ class MultiWalletMiddleware {
globalState?.scanNoteResponse?.card?.cardId?.let {
currenciesRepository.saveAddedToken(it, action.token)
}
addToken(action.token, walletState)
addToken(action.token, walletState, globalState)
}
is WalletAction.MultiWallet.AddTokens -> {
action.tokens.map { addToken(it, walletState) }
action.tokens.map { addToken(it, walletState, globalState) }
}
is WalletAction.MultiWallet.AddBlockchain -> {
globalState?.scanNoteResponse?.card?.let { card ->
@ -62,6 +62,8 @@ 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) }
@ -120,8 +122,15 @@ class MultiWalletMiddleware {
}
}
private fun addToken(token: Token, walletState: WalletState?) {
val walletManager = walletState?.getWalletManager(token.symbol)
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(
card = card,
blockchain = Blockchain.Ethereum
)?.also { walletManager ->
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManager))
}
scope.launch {
val result = walletManager?.addToken(token)
withContext(Dispatchers.Main) {

View file

@ -87,9 +87,18 @@ class WarningsMiddleware {
): WarningMessage? {
if (card.isTwinCard()) return null
if (card.isMultiwalletAllowed) {
return if (card.hasSignedHashes()) {
WarningMessagesManager.signedHashesMultiWalletWarning()
} else {
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
null
}
}
val validator = store.state.walletState.walletManagers.firstOrNull()
as? SignatureCountValidator
return if (validator == null || card.isMultiwalletAllowed) {
return if (validator == null) {
if (card.hasSignedHashes()) {
WarningMessagesManager.alreadySignedHashesWarning()
} else {

View file

@ -225,6 +225,9 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
is WalletAction.ShowDialog.ScanFails -> {
newState = newState.copy(walletDialog = WalletDialog.ScanFailsDialog)
}
is WalletAction.ShowDialog.SignedHashesMultiWalletDialog -> {
newState = newState.copy(walletDialog = WalletDialog.SignedHashesMultiWalletDialog)
}
is WalletAction.HideDialog -> {
newState = newState.copy(walletDialog = null)
}

View file

@ -6,10 +6,14 @@ 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.WalletAction
import com.tangem.tap.features.wallet.redux.WalletData
@ -17,6 +21,11 @@ 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 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
@ -89,16 +98,15 @@ class WalletAdapter
view.card_wallet.setOnClickListener {
store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet))
}
val blockchain = wallet.currencyData.currencySymbol?.let { Blockchain.fromCurrency(it) }
if (blockchain != null && blockchain != Blockchain.Unknown) {
view.tv_token_letter.text = null
view.iv_currency.colorFilter = null
view.iv_currency.setImageResource(blockchain.getIconRes())
} else {
view.tv_token_letter.text = wallet.currencyData.currencySymbol?.take(1)
wallet.token?.getColor()?.let { view.iv_currency.setColorFilter(it) }
view.iv_currency.setImageResource(R.drawable.shape_circle)
}
val blockchain = wallet.blockchain
val token = wallet.token
Picasso.get().loadCurrenciesIcon(
imageView = view.iv_currency,
textView = view.tv_token_letter,
token = token, blockchain = blockchain
)
when (wallet.currencyData.status) {
BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress -> hideWarning()
BalanceStatus.Loading -> {

View file

@ -37,9 +37,11 @@ class WarningMessagesAdapter : ListAdapter<WarningMessage, WarningMessageVH>(Dif
}
object DiffUtilCallback : DiffUtil.ItemCallback<WarningMessage>() {
override fun areContentsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = oldItem == newItem
override fun areContentsTheSame(oldItem: WarningMessage, newItem: WarningMessage) =
oldItem == newItem
override fun areItemsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = oldItem == newItem
override fun areItemsTheSame(oldItem: WarningMessage, newItem: WarningMessage) =
oldItem == newItem
}
}
@ -52,7 +54,8 @@ class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) {
}
private fun setText(warning: WarningMessage) {
fun getString(resId: Int?, default: String) = if (resId == null) default else view.getString(resId)
fun getString(resId: Int?, default: String) =
if (resId == null) default else view.getString(resId)
view.tv_title.text = getString(warning.titleResId, warning.title)
view.tv_message.text = getString(warning.messageResId, warning.message)
@ -67,63 +70,83 @@ class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) {
view.card_view.setCardBackgroundColor(view.context.resources.getColor(color))
}
private fun setupControlButtons(warning: WarningMessage) {
when (warning.type) {
WarningMessage.Type.Permanent -> {
view.group_controls_temporary.hide()
view.group_controls_rating.hide()
}
WarningMessage.Type.Temporary -> {
view.group_controls_rating.hide()
view.group_controls_temporary.show()
view.btn_got_it.setOnClickListener { store.dispatch(GlobalAction.HideWarningMessage(warning)) }
}
WarningMessage.Type.AppRating -> {
view.group_controls_temporary.hide()
view.group_controls_rating.show()
view.btn_close.setOnClickListener {
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_DISMISS)
store.dispatch(GlobalAction.HideWarningMessage(warning))
store.dispatch(WalletAction.Warnings.AppRating.RemindLater)
}
view.btn_can_be_better.setOnClickListener {
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_NEGATIVE)
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
store.dispatch(GlobalAction.HideWarningMessage(warning))
store.dispatch(GlobalAction.SendFeedback(RateCanBeBetterEmail()))
}
view.btn_really_cool.setOnClickListener {
val activity = view.context.getActivity() ?: return@setOnClickListener
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_POSITIVE)
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
val reviewManager = ReviewManagerFactory.create(activity)
val task = reviewManager.requestReviewFlow()
task.addOnCompleteListener {
if (it.isSuccessful) {
val reviewFlow = reviewManager.launchReviewFlow(activity, it.result)
reviewFlow.addOnCompleteListener {
if (it.isSuccessful) {
// send review was succeed
} else {
// send fails
}
}
} else {
Timber.e(task.exception)
private fun setupControlButtons(warning: WarningMessage) = when (warning.type) {
WarningMessage.Type.Permanent -> {
view.group_controls_temporary.hide()
view.group_controls_rating.hide()
}
WarningMessage.Type.Temporary -> {
view.group_controls_rating.hide()
view.group_controls_temporary.show()
val buttonAction =
when (warning.titleResId) {
R.string.warning_important_security_info -> {
View.OnClickListener {
store.dispatch(WalletAction.ShowDialog.SignedHashesMultiWalletDialog)
}
}
else -> {
View.OnClickListener {
store.dispatch(GlobalAction.HideWarningMessage(warning))
}
}.addOnFailureListener {
Timber.e(it)
}
store.dispatch(GlobalAction.HideWarningMessage(warning))
}
val buttonTitle = view.getString(
warning.buttonTextId ?: R.string.how_to_got_it_button
)
view.btn_got_it.setOnClickListener (buttonAction)
view.btn_got_it.text = buttonTitle
}
WarningMessage.Type.AppRating -> {
view.group_controls_temporary.hide()
view.group_controls_rating.show()
view.btn_close.setOnClickListener {
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_DISMISS)
store.dispatch(GlobalAction.HideWarningMessage(warning))
store.dispatch(WalletAction.Warnings.AppRating.RemindLater)
}
view.btn_can_be_better.setOnClickListener {
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_NEGATIVE)
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
store.dispatch(GlobalAction.HideWarningMessage(warning))
store.dispatch(GlobalAction.SendFeedback(RateCanBeBetterEmail()))
}
view.btn_really_cool.setOnClickListener {
val activity = view.context.getActivity() ?: return@setOnClickListener
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.APP_RATING_POSITIVE)
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
val reviewManager = ReviewManagerFactory.create(activity)
val task = reviewManager.requestReviewFlow()
task.addOnCompleteListener {
if (it.isSuccessful) {
val reviewFlow = reviewManager.launchReviewFlow(activity, it.result)
reviewFlow.addOnCompleteListener {
if (it.isSuccessful) {
// send review was succeed
} else {
// send fails
}
}
} else {
Timber.e(task.exception)
}
}.addOnFailureListener {
Timber.e(it)
}
store.dispatch(GlobalAction.HideWarningMessage(warning))
}
}
}
}
class SpacesItemDecoration(private val spacePx: Int) : ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
outRect.left = spacePx
outRect.right = spacePx

View file

@ -0,0 +1,33 @@
package com.tangem.tap.features.wallet.ui.dialogs
import android.content.Context
import androidx.appcompat.app.AlertDialog
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.wallet.R
class SignedHashesWarningDialog {
companion object {
fun create(context: Context): AlertDialog {
return AlertDialog.Builder(context).apply {
setTitle(context.getString(R.string.warning_important_security_info))
setMessage(R.string.alert_signed_hashes_message)
setPositiveButton(R.string.alert_button_i_understand) { _, _ ->
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
store.dispatch(
GlobalAction.HideWarningMessage(
WarningMessagesManager.signedHashesMultiWalletWarning()
)
)
}
setNegativeButton(R.string.common_cancel) { _, _ -> }
setOnDismissListener {
store.dispatch(WalletAction.HideDialog)
}
}.create()
}
}
}

View file

@ -15,6 +15,7 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.WalletFragment
import com.tangem.tap.features.wallet.ui.adapters.WalletAdapter
import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog
import com.tangem.tap.features.wallet.ui.dialogs.SignedHashesWarningDialog
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.card_balance.*
@ -94,24 +95,24 @@ class MultiWalletView : WalletView {
when (state.primaryWallet?.currencyData?.status) {
BalanceStatus.EmptyCard -> {
showErrorState(
fragment,
fragment.getText(R.string.wallet_error_empty_card),
fragment.getString(R.string.wallet_error_empty_card_subtitle)
fragment,
fragment.getText(R.string.wallet_error_empty_card),
fragment.getString(R.string.wallet_error_empty_card_subtitle)
)
configureButtonsForEmptyWalletState(fragment)
}
BalanceStatus.UnknownBlockchain -> {
showErrorState(
fragment,
fragment.getText(R.string.wallet_error_unsupported_blockchain),
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle)
fragment,
fragment.getText(R.string.wallet_error_unsupported_blockchain),
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle)
)
}
}
}
private fun showErrorState(
fragment: WalletFragment, errorTitle: CharSequence, errorDescription: CharSequence,
fragment: WalletFragment, errorTitle: CharSequence, errorDescription: CharSequence,
) = with(fragment) {
l_card_balance.show()
l_balance.hide()
@ -137,6 +138,11 @@ class MultiWalletView : WalletView {
is WalletDialog.ScanFailsDialog -> {
if (dialog == null) dialog = ScanFailsDialog.create(context).apply { show() }
}
is WalletDialog.SignedHashesMultiWalletDialog -> {
if (dialog == null) {
dialog = SignedHashesWarningDialog.create(context).apply { show() }
}
}
else -> {
dialog?.dismiss()
dialog = null

View file

@ -19,6 +19,7 @@ import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog
import com.tangem.tap.features.wallet.ui.dialogs.QrDialog
import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog
import com.tangem.tap.features.wallet.ui.dialogs.SignedHashesWarningDialog
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.card_balance.*
@ -238,6 +239,11 @@ class SingleWalletView : WalletView {
is WalletDialog.ScanFailsDialog -> {
if (dialog == null) dialog = ScanFailsDialog.create(context).apply { show() }
}
is WalletDialog.SignedHashesMultiWalletDialog -> {
if (dialog == null) {
dialog = SignedHashesWarningDialog.create(context).apply { show() }
}
}
null -> {
dialog?.dismiss()
dialog = null

View file

@ -44,6 +44,7 @@ class NetworkConnectivity(
(capabilities != null) &&
(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
} else {

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

@ -103,5 +103,12 @@ this wallet.
<string name="warning_failed_to_verify_card_message" translatable="false">This card might be a production sample or counterfeit</string>
<string name="warning_important_security_info" translatable="false">Important security information \u26A0</string>
<string name="warning_signed_tx_previously" translatable="false">This card has signed transactions in the past</string>
<string name="warning_button_learn_more" translatable="false">Learn more</string>
<string name="alert_signed_hashes_message" translatable="false">This card is not a bearer note. We cant currently match the signature count on the card with the information on the blockchain. This is normal but in rare cases can mean a previous holder is holding back an offline signature, which is a security concern.
\n\nDo not accept this card as physical payment from someone you dont trust.
\n\nIts perfectly safe in all other respects.
\n\nTangem is the only hardware wallet to offer signature count protection.</string>
<string name="alert_button_i_understand" translatable="false">I understand</string>
</resources>

View file

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

View file

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip