Updated on 2026-08-14
This commit is contained in:
parent
e57d8ca630
commit
0571d8bb80
31 changed files with 507 additions and 289 deletions
|
|
@ -75,10 +75,13 @@ dependencies {
|
|||
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
|
||||
implementation 'com.tangem:blockchain:1.166.0'
|
||||
implementation 'com.tangem:core:1.109.0'
|
||||
implementation 'com.tangem:sdk:1.109.0'
|
||||
// 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'
|
||||
|
||||
// WebView
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
|
|
|
|||
|
|
@ -25,16 +25,6 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
is GlobalAction.RestoreAppCurrency.Success -> {
|
||||
globalState.copy(appCurrency = action.appCurrency)
|
||||
}
|
||||
is GlobalAction.UpdateWalletSignedHashes -> {
|
||||
val card = globalState.scanNoteResponse?.card?.copy(
|
||||
walletSignedHashes = action.walletSignedHashes
|
||||
)
|
||||
if (card != null) {
|
||||
globalState.copy(scanNoteResponse = globalState.scanNoteResponse.copy(card = card))
|
||||
} else {
|
||||
globalState
|
||||
}
|
||||
}
|
||||
is GlobalAction.SetConfigManager -> {
|
||||
globalState.copy(configManager = action.configManager)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,16 @@ package com.tangem.tap.domain
|
|||
|
||||
import androidx.activity.ComponentActivity
|
||||
import com.tangem.*
|
||||
import com.tangem.commands.*
|
||||
import com.tangem.commands.CommandResponse
|
||||
import com.tangem.commands.PinType
|
||||
import com.tangem.commands.SetPinCommand
|
||||
import com.tangem.commands.SetPinResponse
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.CardType
|
||||
import com.tangem.commands.wallet.PurgeWalletCommand
|
||||
import com.tangem.commands.wallet.PurgeWalletResponse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.TangemSdkConstants
|
||||
import com.tangem.common.extensions.calculateSha256
|
||||
import com.tangem.tangem_sdk_new.extensions.init
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
|
|
@ -32,13 +38,15 @@ class TangemSdkManager(val activity: ComponentActivity) {
|
|||
initialMessage = Message(activity.getString(R.string.initial_message_scan_header)))
|
||||
}
|
||||
|
||||
suspend fun createWallet(cardId: String?): CompletionResult<ScanNoteResponse> {
|
||||
suspend fun createWallet(cardId: String?): CompletionResult<Card> {
|
||||
return runTaskAsyncReturnOnMain(CreateWalletAndRescanTask(), cardId,
|
||||
initialMessage = Message(activity.getString(R.string.initial_message_create_wallet_body)))
|
||||
}
|
||||
|
||||
suspend fun eraseWallet(cardId: String?): CompletionResult<PurgeWalletResponse> {
|
||||
return runTaskAsyncReturnOnMain(PurgeWalletCommand(), cardId,
|
||||
return runTaskAsyncReturnOnMain(PurgeWalletCommand(
|
||||
TangemSdkConstants.getDefaultWalletIndex()),
|
||||
cardId,
|
||||
initialMessage = Message(activity.getString(R.string.initial_message_purge_wallet_body)))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ import com.tangem.tap.common.redux.global.FiatCurrencyName
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.currenciesRepository
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.domain.extensions.isNoAccountError
|
||||
import com.tangem.tap.domain.extensions.*
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.domain.tokens.CardCurrencies
|
||||
import com.tangem.tap.domain.twins.TwinsHelper
|
||||
|
|
@ -102,8 +101,10 @@ class TapWalletManager {
|
|||
))
|
||||
}
|
||||
}
|
||||
if (data.walletManager?.wallet?.blockchain == Blockchain.Ethereum ||
|
||||
data.walletManager?.wallet?.blockchain == Blockchain.EthereumTestnet) {
|
||||
|
||||
val blockchain = data.card.getBlockchain()
|
||||
if (blockchain == Blockchain.Ethereum ||
|
||||
blockchain == Blockchain.EthereumTestnet) {
|
||||
store.dispatch(TokensAction.LoadCardTokens)
|
||||
}
|
||||
loadData(data)
|
||||
|
|
@ -112,10 +113,11 @@ class TapWalletManager {
|
|||
|
||||
private fun updateConfigManager(data: ScanNoteResponse) {
|
||||
val configManager = store.state.globalState.configManager
|
||||
val blockchain = data.card.getBlockchain()
|
||||
if (TapWorkarounds.isStart2Coin) {
|
||||
configManager?.turnOff(ConfigManager.isSendingToPayIdEnabled)
|
||||
configManager?.turnOff(ConfigManager.isTopUpEnabled)
|
||||
} else if (data.walletManager?.wallet?.blockchain == Blockchain.Bitcoin
|
||||
} else if (blockchain == Blockchain.Bitcoin
|
||||
|| data.card.cardData?.blockchainName == Blockchain.Bitcoin.id) {
|
||||
configManager?.resetToDefault(ConfigManager.isSendingToPayIdEnabled)
|
||||
configManager?.resetToDefault(ConfigManager.isTopUpEnabled)
|
||||
|
|
@ -128,59 +130,77 @@ class TapWalletManager {
|
|||
suspend fun loadData(data: ScanNoteResponse) {
|
||||
withContext(Dispatchers.Main) {
|
||||
val artworkId = data.verifyResponse?.artworkInfo?.id
|
||||
if (data.walletManager != null) {
|
||||
val config = store.state.globalState.configManager?.config ?: return@withContext
|
||||
|
||||
val primaryWalletManager = data.walletManager
|
||||
val primaryBlockchain = data.walletManager.wallet.blockchain
|
||||
val primaryTokenSymbol = data.card.cardData?.tokenSymbol
|
||||
val primaryToken = primaryWalletManager.presetTokens.toList()
|
||||
.firstOrNull { it.symbol == primaryTokenSymbol }
|
||||
|
||||
store.dispatch(WalletAction.MultiWallet.SetPrimaryBlockchain(primaryBlockchain))
|
||||
if (primaryToken != null) {
|
||||
store.dispatch(WalletAction.MultiWallet.SetPrimaryToken(primaryToken))
|
||||
when {
|
||||
data.card.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain))
|
||||
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
|
||||
}
|
||||
if (data.card.isMultiwalletAllowed) {
|
||||
loadMultiWalletData(data.card, primaryBlockchain, primaryWalletManager)
|
||||
} else {
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(primaryBlockchain)))
|
||||
data.card.getStatus() == CardStatus.Empty ||
|
||||
(data.card.isTwinCard() && data.secondTwinPublicKey == null) -> {
|
||||
store.dispatch(WalletAction.EmptyWallet)
|
||||
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
|
||||
}
|
||||
else -> {
|
||||
val config = store.state.globalState.configManager?.config ?: return@withContext
|
||||
|
||||
val blockchain = data.card.getBlockchain()
|
||||
val primaryWalletManager = if (blockchain != null) {
|
||||
walletManagerFactory.makeWalletManagerForApp(data.card, blockchain)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
if (blockchain != null && primaryWalletManager != null) {
|
||||
val primaryToken = data.card.getToken()
|
||||
|
||||
store.dispatch(WalletAction.MultiWallet.SetPrimaryBlockchain(blockchain))
|
||||
if (primaryToken != null) {
|
||||
primaryWalletManager.addToken(primaryToken)
|
||||
store.dispatch(WalletAction.MultiWallet.SetPrimaryToken(primaryToken))
|
||||
}
|
||||
if (data.card.isMultiwalletAllowed) {
|
||||
loadMultiWalletData(data.card, blockchain, primaryWalletManager)
|
||||
} else {
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(blockchain)))
|
||||
}
|
||||
|
||||
} else {
|
||||
if (data.card.isMultiwalletAllowed) {
|
||||
loadMultiWalletData(data.card, blockchain, null)
|
||||
}
|
||||
}
|
||||
store.dispatch(WalletAction.SetArtworkId(data.verifyResponse?.artworkInfo?.id))
|
||||
store.dispatch(WalletAction.LoadWallet(config.isTopUpEnabled))
|
||||
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
|
||||
store.dispatch(WalletAction.LoadFiatRate())
|
||||
}
|
||||
store.dispatch(WalletAction.SetArtworkId(data.verifyResponse?.artworkInfo?.id))
|
||||
store.dispatch(WalletAction.LoadWallet(config.isTopUpEnabled))
|
||||
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
|
||||
store.dispatch(WalletAction.LoadFiatRate())
|
||||
} else if (data.card.status == CardStatus.Empty || data.card.isTwinCard()) {
|
||||
store.dispatch(WalletAction.EmptyWallet)
|
||||
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
|
||||
} else {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain))
|
||||
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
|
||||
}
|
||||
store.dispatch(WalletAction.Warnings.CheckIfNeeded)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMultiWalletData(
|
||||
card: Card, primaryBlockchain: Blockchain, primaryWalletManager: WalletManager
|
||||
card: Card, primaryBlockchain: Blockchain?, primaryWalletManager: WalletManager?
|
||||
) {
|
||||
val presetTokens = primaryWalletManager.presetTokens.toList()
|
||||
val presetTokens = primaryWalletManager?.presetTokens?.toList() ?: emptyList()
|
||||
val savedCurrencies = currenciesRepository.loadCardCurrencies(card.cardId)
|
||||
|
||||
if (savedCurrencies == null) {
|
||||
store.dispatch(WalletAction.MultiWallet.SaveCurrencies(
|
||||
CardCurrencies(
|
||||
blockchains = listOf(primaryBlockchain), tokens = presetTokens
|
||||
)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(primaryBlockchain)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddTokens(presetTokens))
|
||||
if (primaryBlockchain != null && primaryWalletManager != null) {
|
||||
store.dispatch(WalletAction.MultiWallet.SaveCurrencies(
|
||||
CardCurrencies(
|
||||
blockchains = listOf(primaryBlockchain), tokens = presetTokens
|
||||
)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(primaryBlockchain)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddTokens(presetTokens))
|
||||
}
|
||||
store.dispatch(WalletAction.MultiWallet.FindBlockchainsInUse(card, walletManagerFactory))
|
||||
store.dispatch(WalletAction.MultiWallet.FindTokensInUse)
|
||||
} else {
|
||||
val blockchains = listOf(primaryBlockchain) + savedCurrencies.blockchains
|
||||
val walletManagers = walletManagerFactory.makeWalletManagers(card, blockchains)
|
||||
val blockchains = listOfNotNull(primaryBlockchain) + savedCurrencies.blockchains
|
||||
val walletManagers = walletManagerFactory.makeWalletManagersForApp(card, blockchains)
|
||||
val tokens = presetTokens + savedCurrencies.tokens
|
||||
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManagers))
|
||||
|
|
@ -192,18 +212,23 @@ class TapWalletManager {
|
|||
|
||||
suspend fun reloadData(data: ScanNoteResponse) {
|
||||
withContext(Dispatchers.Main) {
|
||||
if (data.walletManager != null) {
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection))
|
||||
return@withContext
|
||||
when {
|
||||
data.card.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain))
|
||||
}
|
||||
data.card.getStatus() == CardStatus.Empty ||
|
||||
(data.card.isTwinCard() && data.secondTwinPublicKey == null) -> {
|
||||
store.dispatch(WalletAction.EmptyWallet)
|
||||
}
|
||||
else -> {
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection))
|
||||
return@withContext
|
||||
}
|
||||
val config = store.state.globalState.configManager?.config ?: return@withContext
|
||||
store.dispatch(WalletAction.LoadWallet(config.isTopUpEnabled))
|
||||
store.dispatch(WalletAction.LoadFiatRate())
|
||||
}
|
||||
val config = store.state.globalState.configManager?.config ?: return@withContext
|
||||
store.dispatch(WalletAction.LoadWallet(config.isTopUpEnabled))
|
||||
store.dispatch(WalletAction.LoadFiatRate())
|
||||
} else if (data.card.status == CardStatus.Empty || data.card.isTwinCard()) {
|
||||
store.dispatch(WalletAction.EmptyWallet)
|
||||
} else {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ object TapWorkarounds {
|
|||
"0030",
|
||||
"0031",
|
||||
"0035"
|
||||
) // Tangem tags
|
||||
)
|
||||
|
||||
private val excludedIssuers = listOf(
|
||||
"TTM BANK"
|
||||
|
|
@ -43,5 +43,6 @@ val Card.isMultiwalletAllowed: Boolean
|
|||
get() {
|
||||
return cardData?.productMask?.contains(Product.TwinCard) != true
|
||||
&& !TapWorkarounds.isStart2Coin
|
||||
&& this.curve == EllipticCurve.Secp256k1
|
||||
&& (this.firmwareVersion.major >= 4 ||
|
||||
this.getWallets().getOrNull(0)?.curve == EllipticCurve.Secp256k1)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.domain.extensions
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.commands.common.card.EllipticCurve
|
||||
import org.stellar.sdk.requests.ErrorResponse
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -28,4 +29,15 @@ fun Blockchain.minimalAmount(): BigDecimal {
|
|||
return 1.toBigDecimal().movePointLeft(decimals())
|
||||
}
|
||||
|
||||
fun Blockchain.getCurve(): EllipticCurve? {
|
||||
return when (this) {
|
||||
Blockchain.Unknown -> null
|
||||
Blockchain.Bitcoin, Blockchain.BitcoinTestnet, Blockchain.BitcoinCash, Blockchain.Litecoin,
|
||||
Blockchain.Ducatus, Blockchain.Ethereum, Blockchain.EthereumTestnet, Blockchain.RSK,
|
||||
Blockchain.Tezos, Blockchain.XRP, Blockchain.Binance, Blockchain.BinanceTestnet ->
|
||||
EllipticCurve.Secp256k1
|
||||
Blockchain.Cardano, Blockchain.CardanoShelley, Blockchain.Stellar -> EllipticCurve.Ed25519
|
||||
}
|
||||
}
|
||||
|
||||
private const val NODL = "NODL"
|
||||
44
app/src/main/java/com/tangem/tap/domain/extensions/Card.kt
Normal file
44
app/src/main/java/com/tangem/tap/domain/extensions/Card.kt
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.tap.domain.extensions
|
||||
|
||||
import com.tangem.FirmwareConstraints
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.CardStatus
|
||||
import com.tangem.commands.wallet.CardWallet
|
||||
import com.tangem.commands.wallet.WalletStatus
|
||||
import com.tangem.common.TangemSdkConstants
|
||||
|
||||
fun Card.getToken(): Token? {
|
||||
val symbol = cardData?.tokenSymbol ?: return null
|
||||
val contractAddress = cardData?.tokenContractAddress ?: return null
|
||||
val decimals = cardData?.tokenDecimal ?: return null
|
||||
return Token(symbol, contractAddress, decimals)
|
||||
}
|
||||
|
||||
fun Card.getBlockchain(): Blockchain? {
|
||||
val blockchainName: String = cardData?.blockchainName ?: return null
|
||||
return Blockchain.fromId(blockchainName)
|
||||
}
|
||||
|
||||
fun Card.getSingleWallet(): CardWallet? {
|
||||
return wallet(TangemSdkConstants.getDefaultWalletIndex())
|
||||
}
|
||||
|
||||
fun Card.getStatus(): CardStatus {
|
||||
if (firmwareVersion < FirmwareConstraints.AvailabilityVersions.walletData) return status!!
|
||||
|
||||
return if (getWallets().any { it.status == WalletStatus.Loaded }) {
|
||||
CardStatus.Loaded
|
||||
} else {
|
||||
CardStatus.Empty
|
||||
}
|
||||
}
|
||||
|
||||
fun Card.hasSignedHashes(): Boolean {
|
||||
return getWallets().any { it.status == WalletStatus.Loaded && it.signedHashes ?: 0 > 0 }
|
||||
}
|
||||
|
||||
fun Card.signedHashesCount(): Int {
|
||||
return getWallets().map { it.signedHashes ?: 0 }.sum()
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.domain.extensions
|
||||
|
||||
import com.tangem.commands.wallet.WalletIndex
|
||||
import com.tangem.common.TangemSdkConstants
|
||||
|
||||
fun TangemSdkConstants.Companion.getDefaultWalletIndex(): WalletIndex {
|
||||
return WalletIndex.Index(oldCardDefaultWalletIndex)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.tap.domain.extensions
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.EllipticCurve
|
||||
|
||||
fun WalletManagerFactory.makeWalletManagerForApp(card: Card, blockchain: Blockchain): WalletManager? {
|
||||
val curve = blockchain.getCurve() ?: return null
|
||||
val publicKey = card.getWallets().firstOrNull { it.curve == curve }?.publicKey ?: return null
|
||||
return makeWalletManager(card.cardId, publicKey, blockchain, curve)
|
||||
}
|
||||
|
||||
fun WalletManagerFactory.makeWalletManagersForApp(
|
||||
card: Card, blockchains: List<Blockchain>
|
||||
): List<WalletManager> {
|
||||
return makeWalletManagersForCurve(card, blockchains, EllipticCurve.Secp256k1) +
|
||||
makeWalletManagersForCurve(card, blockchains, EllipticCurve.Ed25519)
|
||||
}
|
||||
|
||||
fun WalletManagerFactory.makeWalletManagersForCurve(
|
||||
card: Card, blockchains: List<Blockchain>, curve: EllipticCurve
|
||||
): List<WalletManager> {
|
||||
val blockchainsForCurve = blockchains.filter { it.getCurve() == curve }
|
||||
val walletPublicKey = card.getWallets().firstOrNull { it.curve == curve }?.publicKey
|
||||
|
||||
return if (walletPublicKey != null) {
|
||||
makeWalletManagers(card.cardId, walletPublicKey, blockchainsForCurve, curve)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
|
@ -2,26 +2,39 @@ package com.tangem.tap.domain.tasks
|
|||
|
||||
import com.tangem.CardSession
|
||||
import com.tangem.CardSessionRunnable
|
||||
import com.tangem.commands.ReadCommand
|
||||
import com.tangem.FirmwareConstraints
|
||||
import com.tangem.TangemSdkError
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tasks.CreateWalletTask
|
||||
import com.tangem.tasks.PreflightReadCapable
|
||||
import com.tangem.tasks.PreflightReadSettings
|
||||
import com.tangem.tasks.PreflightReadTask
|
||||
|
||||
class CreateWalletAndRescanTask : CardSessionRunnable<ScanNoteResponse> {
|
||||
class CreateWalletAndRescanTask : CardSessionRunnable<Card>, PreflightReadCapable {
|
||||
override val requiresPin2 = false
|
||||
override fun preflightReadSettings() = PreflightReadSettings.FullCardRead
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<ScanNoteResponse>) -> Unit) {
|
||||
CreateWalletTask().run(session) { result ->
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
|
||||
val firmwareVerion = session.environment.card?.firmwareVersion
|
||||
if (firmwareVerion == null) {
|
||||
callback(CompletionResult.Failure(TangemSdkError.CardError()))
|
||||
return
|
||||
}
|
||||
val task = if (firmwareVerion < FirmwareConstraints.AvailabilityVersions.walletData) {
|
||||
CreateWalletTask()
|
||||
} else {
|
||||
CreateWalletsTask()
|
||||
}
|
||||
|
||||
task.run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
ReadCommand().run(session) { readResult ->
|
||||
when (readResult) {
|
||||
is CompletionResult.Success -> ScanNoteTask(readResult.data).run(session, callback)
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(readResult.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
is CompletionResult.Success ->
|
||||
PreflightReadTask(PreflightReadSettings.FullCardRead).run(session, callback)
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.tangem.tap.domain.tasks
|
||||
|
||||
import com.tangem.CardSession
|
||||
import com.tangem.CardSessionRunnable
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.EllipticCurve
|
||||
import com.tangem.commands.wallet.CreateWalletCommand
|
||||
import com.tangem.commands.wallet.WalletConfig
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tasks.PreflightReadSettings
|
||||
import com.tangem.tasks.PreflightReadTask
|
||||
|
||||
class CreateWalletsTask(wallets: List<WalletConfig> = emptyList()) : CardSessionRunnable<Card> {
|
||||
override val requiresPin2 = false
|
||||
|
||||
val wallets = if (wallets.isEmpty()) {
|
||||
listOf(
|
||||
WalletConfig(null, null, EllipticCurve.Secp256k1, null),
|
||||
WalletConfig(null, null, EllipticCurve.Ed25519, null),
|
||||
WalletConfig(null, null, EllipticCurve.Secp256r1, null),
|
||||
)
|
||||
} else {
|
||||
wallets
|
||||
}
|
||||
|
||||
var index = 0
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
|
||||
val walletConfig = wallets[index]
|
||||
createWallet(walletConfig, session, callback)
|
||||
}
|
||||
|
||||
private fun createWallet(
|
||||
walletConfig: WalletConfig, session: CardSession,
|
||||
callback: (result: CompletionResult<Card>) -> Unit
|
||||
) {
|
||||
|
||||
CreateWalletCommand(
|
||||
walletConfig, walletIndexValue = walletConfig.curveId!!.toWalletIndex()
|
||||
).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
if (index == wallets.lastIndex) {
|
||||
PreflightReadTask(PreflightReadSettings.FullCardRead).run(session, callback)
|
||||
return@run
|
||||
}
|
||||
index += 1
|
||||
createWallet(wallets[index], session, callback)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun EllipticCurve.toWalletIndex(): Int {
|
||||
return when (this) {
|
||||
EllipticCurve.Secp256k1 -> 0
|
||||
EllipticCurve.Ed25519 -> 1
|
||||
EllipticCurve.Secp256r1 -> 2
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +1,40 @@
|
|||
package com.tangem.tap.domain.tasks
|
||||
|
||||
import com.tangem.*
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import com.tangem.commands.CommandResponse
|
||||
import com.tangem.commands.ReadIssuerDataCommand
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.CardStatus
|
||||
import com.tangem.commands.verifycard.VerifyCardCommand
|
||||
import com.tangem.commands.verifycard.VerifyCardResponse
|
||||
import com.tangem.commands.common.card.EllipticCurve
|
||||
import com.tangem.commands.verification.VerifyCardCommand
|
||||
import com.tangem.commands.verification.VerifyCardResponse
|
||||
import com.tangem.commands.wallet.WalletConfig
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.tap.domain.TapSdkError
|
||||
import com.tangem.tap.domain.TapWorkarounds.isExcluded
|
||||
import com.tangem.tap.domain.isMultiwalletAllowed
|
||||
import com.tangem.tap.domain.extensions.getSingleWallet
|
||||
import com.tangem.tap.domain.extensions.getStatus
|
||||
import com.tangem.tap.domain.twins.TwinCardsManager
|
||||
import com.tangem.tap.domain.twins.isTwinCard
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tasks.PreflightReadCapable
|
||||
import com.tangem.tasks.PreflightReadSettings
|
||||
import com.tangem.tasks.ScanTask
|
||||
|
||||
data class ScanNoteResponse(
|
||||
val walletManager: WalletManager?,
|
||||
val card: Card,
|
||||
val verifyResponse: VerifyCardResponse? = null,
|
||||
val secondTwinPublicKey: String? = null,
|
||||
) : CommandResponse
|
||||
|
||||
class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteResponse> {
|
||||
class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteResponse>, PreflightReadCapable {
|
||||
override val requiresPin2 = false
|
||||
|
||||
override fun preflightReadSettings() = PreflightReadSettings.FullCardRead
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<ScanNoteResponse>) -> Unit) {
|
||||
ScanTask().run(session) { result ->
|
||||
when (result) {
|
||||
|
|
@ -48,39 +52,25 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
|
|||
return@run
|
||||
}
|
||||
|
||||
if (card.isTwinCard()) {
|
||||
dealWithTwinCard(card, session, callback)
|
||||
return@run
|
||||
}
|
||||
|
||||
val walletManager = try {
|
||||
getWalletManagerFactory().makeWalletManager(card)
|
||||
} catch (exception: Exception) {
|
||||
if (card.isMultiwalletAllowed) {
|
||||
// Create default Bitcoin WalletManager
|
||||
getWalletManagerFactory().makeWalletManager(card, Blockchain.Bitcoin)
|
||||
} else {
|
||||
return@run callback(CompletionResult.Success(
|
||||
ScanNoteResponse(null, card)
|
||||
))
|
||||
}
|
||||
}
|
||||
verifyCard(walletManager, card, null, session, callback)
|
||||
verifyCard(card, session, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun verifyCard(
|
||||
walletManager: WalletManager?, card: Card, publicKey: String? = null,
|
||||
session: CardSession, callback: (result: CompletionResult<ScanNoteResponse>) -> Unit
|
||||
card: Card, session: CardSession, callback: (result: CompletionResult<ScanNoteResponse>) -> Unit
|
||||
) {
|
||||
|
||||
VerifyCardCommand(true).run(session) { verifyResult ->
|
||||
when (verifyResult) {
|
||||
is CompletionResult.Success -> {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(
|
||||
walletManager, card, verifyResult.data, publicKey)))
|
||||
if (card.isTwinCard()) {
|
||||
dealWithTwinCard(card, session, verifyResult.data, callback)
|
||||
} else if (card.firmwareVersion.major >= 4) {
|
||||
createMissingWalletsIfNeeded(card, session, verifyResult.data, callback)
|
||||
} else {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(card, verifyResult.data)))
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
callback(CompletionResult.Failure(TangemSdkError.CardVerificationFailed()))
|
||||
|
|
@ -89,39 +79,73 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
|
|||
}
|
||||
}
|
||||
|
||||
private fun createMissingWalletsIfNeeded(
|
||||
card: Card, session: CardSession, verifyResponse: VerifyCardResponse,
|
||||
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit
|
||||
) {
|
||||
if (card.getStatus() == CardStatus.Empty) {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(card, verifyResponse)))
|
||||
return
|
||||
}
|
||||
|
||||
val curvesPresent = card.getWallets().map { it.curve }
|
||||
val curvesToCreate = EllipticCurve.values().subtract(curvesPresent)
|
||||
|
||||
if (curvesToCreate.isEmpty()) {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(card, verifyResponse)))
|
||||
return
|
||||
}
|
||||
|
||||
val configs = curvesToCreate.map { curve ->
|
||||
WalletConfig(
|
||||
isReusable = null, prohibitPurgeWallet = null, curveId = curve,
|
||||
signingMethods = null
|
||||
)
|
||||
}
|
||||
CreateWalletsTask(configs).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success ->
|
||||
callback(CompletionResult.Success(ScanNoteResponse(result.data, verifyResponse)))
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun dealWithTwinCard(
|
||||
card: Card, session: CardSession,
|
||||
card: Card, session: CardSession, verifyResponse: VerifyCardResponse,
|
||||
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit
|
||||
) {
|
||||
ReadIssuerDataCommand().run(session) { readDataResult ->
|
||||
when (readDataResult) {
|
||||
is CompletionResult.Success -> {
|
||||
val publicKey = card.getSingleWallet()?.publicKey
|
||||
if (publicKey == null) {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
|
||||
return@run
|
||||
}
|
||||
val verified = TwinCardsManager.verifyTwinPublicKey(
|
||||
readDataResult.data.issuerData, card.walletPublicKey
|
||||
readDataResult.data.issuerData, publicKey
|
||||
)
|
||||
if (verified) {
|
||||
val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65)
|
||||
val walletManager = try {
|
||||
getWalletManagerFactory().makeMultisigWalletManager(card, twinPublicKey)
|
||||
} catch (exception: Exception) {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(null, card)))
|
||||
return@run
|
||||
}
|
||||
verifyCard(walletManager, card, twinPublicKey.toHexString(), session, callback)
|
||||
callback(CompletionResult.Success(
|
||||
ScanNoteResponse(card, verifyResponse, twinPublicKey.toHexString())
|
||||
))
|
||||
return@run
|
||||
} else {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(null, card)))
|
||||
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
callback(CompletionResult.Success(ScanNoteResponse(null, card)))
|
||||
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getErrorIfExcludedCard(card: Card): TangemError? {
|
||||
if (card.isExcluded()) return TapSdkError.CardForDifferentApp
|
||||
if (card.status == CardStatus.Purged) return TangemSdkError.CardIsPurged()
|
||||
if (card.status == CardStatus.Purged) return TangemSdkError.WalletIsPurged()
|
||||
if (card.status == CardStatus.NotPersonalized) return TangemSdkError.NotPersonalized()
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.squareup.moshi.JsonClass
|
|||
import com.squareup.moshi.Types
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.commands.common.card.FirmwareVersion
|
||||
import com.tangem.tap.common.extensions.readJsonFileToString
|
||||
import com.tangem.tap.network.createMoshi
|
||||
|
||||
|
|
@ -93,19 +94,27 @@ class CurrenciesRepository(val context: Application) {
|
|||
return tokensAdapter.fromJson(json)!!.map { it.toToken() }
|
||||
}
|
||||
|
||||
fun getBlockchains(): List<Blockchain> {
|
||||
return listOf(
|
||||
Blockchain.Bitcoin, Blockchain.BitcoinCash, Blockchain.Binance, Blockchain.Litecoin,
|
||||
Blockchain.XRP, Blockchain.Tezos,
|
||||
Blockchain.Ethereum, Blockchain.RSK)
|
||||
fun getBlockchains(cardFirmware: FirmwareVersion?): List<Blockchain> {
|
||||
return if (cardFirmware == null || cardFirmware.major < 4) {
|
||||
secp256k1Blochcains
|
||||
} else {
|
||||
secp256k1Blochcains + ed25519Blockchains
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val POPULAR_TOKENS_FILE_NAME = "erc20_tokens"
|
||||
private const val FILE_NAME_PREFIX_TOKENS = "tokens"
|
||||
private const val FILE_NAME_PREFIX_BLOCKCHAINS = "blockchains"
|
||||
|
||||
fun getFileNameForTokens(cardId: String): String = "${FILE_NAME_PREFIX_TOKENS}_$cardId"
|
||||
fun getFileNameForBlockchains(cardId: String): String = "${FILE_NAME_PREFIX_BLOCKCHAINS}_$cardId"
|
||||
|
||||
private val secp256k1Blochcains = listOf(
|
||||
Blockchain.Bitcoin, Blockchain.BitcoinCash, Blockchain.Binance, Blockchain.Litecoin,
|
||||
Blockchain.XRP, Blockchain.Tezos,
|
||||
Blockchain.Ethereum, Blockchain.RSK)
|
||||
private val ed25519Blockchains = listOf(Blockchain.CardanoShelley, Blockchain.Stellar)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,18 +2,20 @@ package com.tangem.tap.domain.twins
|
|||
|
||||
import com.tangem.CardSession
|
||||
import com.tangem.CardSessionRunnable
|
||||
import com.tangem.commands.CreateWalletResponse
|
||||
import com.tangem.commands.PurgeWalletCommand
|
||||
import com.tangem.commands.common.card.CardStatus
|
||||
import com.tangem.commands.wallet.CreateWalletResponse
|
||||
import com.tangem.commands.wallet.PurgeWalletCommand
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.TangemSdkConstants
|
||||
import com.tangem.tap.domain.extensions.getSingleWallet
|
||||
import com.tangem.tasks.CreateWalletTask
|
||||
|
||||
class CreateFirstTwinWalletTask : CardSessionRunnable<CreateWalletResponse> {
|
||||
override val requiresPin2 = false
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
|
||||
if (session.environment.card?.walletPublicKey != null) {
|
||||
PurgeWalletCommand().run(session) { response ->
|
||||
if (session.environment.card?.getSingleWallet()?.publicKey != null) {
|
||||
PurgeWalletCommand(TangemSdkConstants.getDefaultWalletIndex()).run(session) { response ->
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
session.environment.card = session.environment.card?.copy(status = CardStatus.Empty)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ package com.tangem.tap.domain.twins
|
|||
import com.tangem.CardSession
|
||||
import com.tangem.CardSessionRunnable
|
||||
import com.tangem.Message
|
||||
import com.tangem.commands.CreateWalletResponse
|
||||
import com.tangem.commands.PurgeWalletCommand
|
||||
import com.tangem.commands.common.card.CardStatus
|
||||
import com.tangem.commands.wallet.CreateWalletResponse
|
||||
import com.tangem.commands.wallet.PurgeWalletCommand
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.TangemSdkConstants
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.tap.domain.extensions.getSingleWallet
|
||||
import com.tangem.tasks.CreateWalletTask
|
||||
|
||||
class CreateSecondTwinWalletTask(
|
||||
|
|
@ -18,9 +20,9 @@ class CreateSecondTwinWalletTask(
|
|||
override val requiresPin2 = true
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
|
||||
if (session.environment.card?.walletPublicKey != null) {
|
||||
if (session.environment.card?.getSingleWallet()?.publicKey != null) {
|
||||
session.setInitialMessage(preparingMessage)
|
||||
PurgeWalletCommand().run(session) { response ->
|
||||
PurgeWalletCommand(TangemSdkConstants.getDefaultWalletIndex()).run(session) { response ->
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
session.environment.card =
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.tap.domain.twins
|
|||
import com.tangem.CardSession
|
||||
import com.tangem.CardSessionRunnable
|
||||
import com.tangem.KeyPair
|
||||
import com.tangem.commands.ReadCommand
|
||||
import com.tangem.commands.read.ReadCommand
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.domain.tasks.ScanNoteTask
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.KeyPair
|
|||
import com.tangem.TangemSdkError
|
||||
import com.tangem.commands.*
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.TangemSdkConstants
|
||||
import com.tangem.common.extensions.calculateSha256
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.files.FileHashHelper
|
||||
|
|
@ -17,14 +18,14 @@ class WriteProtectedIssuerDataTask(
|
|||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<WriteIssuerDataResponse>) -> Unit) {
|
||||
val hashes = arrayOf(twinPublicKey.calculateSha256())
|
||||
SignCommand(hashes).run(session) { signResult ->
|
||||
SignCommand(hashes, TangemSdkConstants.getDefaultWalletIndex()).run(session) { signResult ->
|
||||
when (signResult) {
|
||||
is CompletionResult.Success -> {
|
||||
ReadIssuerDataCommand().run(session) { readResult ->
|
||||
when (readResult) {
|
||||
is CompletionResult.Success -> {
|
||||
writeIssuerData(
|
||||
twinPublicKey, issuerKeys, signResult.data.signature,
|
||||
twinPublicKey, issuerKeys, signResult.data.signatures[0],
|
||||
readResult.data, session, callback
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,6 +203,5 @@ private fun prepareAllowedSecurityOptions(card: Card): EnumSet<SecurityOption> {
|
|||
private fun Card.toCardInfo(): CardInfo? {
|
||||
val cardId = this.cardId.chunked(4).joinToString(separator = " ")
|
||||
val issuer = this.cardData?.issuerName ?: return null
|
||||
val signedHashes = this.walletSignedHashes ?: return null
|
||||
return CardInfo(cardId, issuer, signedHashes)
|
||||
return CardInfo(cardId, issuer)
|
||||
}
|
||||
|
|
@ -26,7 +26,6 @@ data class DetailsState(
|
|||
data class CardInfo(
|
||||
val cardId: String,
|
||||
val issuer: String,
|
||||
val signedHashes: Int,
|
||||
)
|
||||
|
||||
enum class EraseWalletState { Allowed, NotAllowedByCard, NotEmpty }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class CreateTwinWalletMiddleware {
|
|||
fun handle(action: DetailsAction.CreateTwinWalletAction) {
|
||||
when (action) {
|
||||
is DetailsAction.CreateTwinWalletAction.ShowWarning -> {
|
||||
val wallet = store.state.globalState.scanNoteResponse?.walletManager?.wallet
|
||||
val wallet = store.state.detailsState.wallets.firstOrNull()
|
||||
if (wallet == null) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.CreateTwinWalletWarning))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -74,12 +74,8 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
}
|
||||
tv_card_id.text = cardId
|
||||
tv_issuer.text = state.cardInfo.issuer
|
||||
tv_signed_hashes.text = state.cardInfo.signedHashes.toString()
|
||||
}
|
||||
|
||||
tv_signed_hashes.show(state.card?.isTwinCard() != true)
|
||||
tv_signed_hashes_title.show(state.card?.isTwinCard() != true)
|
||||
|
||||
tv_disclaimer.setOnClickListener { store.dispatch(DetailsAction.ShowDisclaimer) }
|
||||
|
||||
tv_card_tou.show(state.cardTermsOfUseUrl != null)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.domain.extensions.signedHashesCount
|
||||
import com.tangem.tap.store
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
|
@ -161,7 +162,7 @@ class AdditionalEmailInfo {
|
|||
fun setCardInfo(card: Card) {
|
||||
cardId = card.cardId
|
||||
cardFirmwareVersion = card.firmwareVersion.version
|
||||
signedHashesCount = card.walletSignedHashes?.toString() ?: "0"
|
||||
signedHashesCount = card.signedHashesCount().toString()
|
||||
}
|
||||
|
||||
fun setWalletsInfo(wallets: List<Wallet>) {
|
||||
|
|
@ -274,7 +275,6 @@ class FeedbackEmail : EmailData {
|
|||
val builder = StringBuilder()
|
||||
builder.appendKeyValue("Card ID", infoHolder.cardId)
|
||||
builder.appendKeyValue("Firmware version", infoHolder.cardFirmwareVersion)
|
||||
builder.appendKeyValue("Signed hashes", infoHolder.signedHashesCount)
|
||||
|
||||
infoHolder.walletsInfo.forEach {
|
||||
builder.appendKeyValue("Blockchain", it.blockchain.fullName)
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|||
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
|
||||
import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.blockchain.extensions.Signer
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.TapWorkarounds
|
||||
|
|
@ -115,11 +114,10 @@ private fun sendTransaction(
|
|||
val result = (walletManager as TransactionSender).send(txData, signer)
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
is SimpleResult.Success -> {
|
||||
tangemSdk.config.linkedTerminal = isLinkedTerminal
|
||||
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.TRANSACTION_IS_SENT, card)
|
||||
dispatch(SendAction.SendSuccess)
|
||||
dispatch(GlobalAction.UpdateWalletSignedHashes(result.data.walletSignedHashes))
|
||||
dispatch(NavigationAction.PopBackTo())
|
||||
scope.launch(Dispatchers.IO) {
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
@ -131,7 +129,7 @@ private fun sendTransaction(
|
|||
}
|
||||
}
|
||||
}
|
||||
is Result.Failure -> {
|
||||
is SimpleResult.Failure -> {
|
||||
when (result.error) {
|
||||
is CreateAccountUnderfunded -> {
|
||||
val error = result.error as CreateAccountUnderfunded
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import com.tangem.tap.common.CurrencyConverter
|
|||
import com.tangem.tap.features.send.redux.*
|
||||
import com.tangem.tap.features.send.redux.states.IdStateHolder
|
||||
import com.tangem.tap.features.send.redux.states.SendState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Action
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -60,8 +59,7 @@ private class EmptyReducer : SendInternalReducer {
|
|||
private class PrepareSendScreenStatesReducer : SendInternalReducer {
|
||||
override fun handle(action: SendScreenAction, sendState: SendState): SendState {
|
||||
val prepareAction = action as PrepareSendScreen
|
||||
val walletManager = action.walletManager
|
||||
?: store.state.globalState.scanNoteResponse!!.walletManager!!
|
||||
val walletManager = action.walletManager!!
|
||||
val amountToExtract = prepareAction.tokenAmount ?: prepareAction.coinAmount!!
|
||||
val decimals = amountToExtract.decimals
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@ class TokensMiddleware {
|
|||
{ action ->
|
||||
when (action) {
|
||||
is TokensAction.LoadCurrencies -> {
|
||||
val cardFirmware = state()?.globalState?.scanNoteResponse?.card?.firmwareVersion
|
||||
val tokens = currenciesRepository.getPopularTokens()
|
||||
val blockchains = currenciesRepository.getBlockchains()
|
||||
val blockchains = currenciesRepository.getBlockchains(cardFirmware)
|
||||
val currencies = CurrencyListItem.createListOfCurrencies(
|
||||
blockchains, tokens
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import com.tangem.tap.common.redux.global.GlobalState
|
|||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.currenciesRepository
|
||||
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
|
||||
import com.tangem.tap.domain.extensions.makeWalletManagersForApp
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.scope
|
||||
|
|
@ -46,7 +48,7 @@ class MultiWalletMiddleware {
|
|||
globalState?.scanNoteResponse?.card?.let { card ->
|
||||
currenciesRepository.saveAddedBlockchain(card.cardId, action.blockchain)
|
||||
globalState.tapWalletManager.walletManagerFactory
|
||||
.makeWalletManager(card, action.blockchain)?.let {
|
||||
.makeWalletManagerForApp(card, action.blockchain)?.let {
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(it))
|
||||
}
|
||||
}
|
||||
|
|
@ -66,9 +68,10 @@ class MultiWalletMiddleware {
|
|||
}
|
||||
}
|
||||
is WalletAction.MultiWallet.FindBlockchainsInUse -> {
|
||||
val blockchains = currenciesRepository.getBlockchains()
|
||||
val cardFirmware = globalState?.scanNoteResponse?.card?.firmwareVersion
|
||||
val blockchains = currenciesRepository.getBlockchains(cardFirmware)
|
||||
.filterNot { walletState?.blockchains?.contains(it) == true }
|
||||
val walletManagers = action.factory.makeWalletManagers(action.card, blockchains)
|
||||
val walletManagers = action.factory.makeWalletManagersForApp(action.card, blockchains)
|
||||
|
||||
scope.launch {
|
||||
walletManagers.map { walletManager ->
|
||||
|
|
|
|||
|
|
@ -108,7 +108,11 @@ class WalletMiddleware {
|
|||
)
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
globalState?.tapWalletManager?.onCardScanned(result.data)
|
||||
val scanNoteResponse =
|
||||
globalState?.scanNoteResponse?.copy(card = result.data)
|
||||
scanNoteResponse?.let {
|
||||
globalState.tapWalletManager.onCardScanned(scanNoteResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.blockchain.common.Wallet
|
|||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.CardType
|
||||
import com.tangem.commands.verifycard.VerifyCardState
|
||||
import com.tangem.commands.verification.VerifyCardState
|
||||
import com.tangem.common.extensions.getType
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
|
|
@ -14,6 +14,8 @@ import com.tangem.tap.common.extensions.isGreaterThan
|
|||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.domain.extensions.getSingleWallet
|
||||
import com.tangem.tap.domain.extensions.hasSignedHashes
|
||||
import com.tangem.tap.domain.isMultiwalletAllowed
|
||||
import com.tangem.tap.domain.twins.isTwinCard
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
|
|
@ -63,13 +65,12 @@ class WarningsMiddleware {
|
|||
}
|
||||
|
||||
private fun showCardWarningsIfNeeded(globalState: GlobalState?) {
|
||||
val validator = globalState?.scanNoteResponse?.walletManager as? SignatureCountValidator
|
||||
globalState?.scanNoteResponse?.card?.let { card ->
|
||||
globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local)
|
||||
if (card.getType() != CardType.Release) {
|
||||
addWarningMessage(WarningMessagesManager.devCardWarning())
|
||||
} else if (!preferencesStorage.wasCardScannedBefore(card.cardId)) {
|
||||
checkIfWarningNeeded(card, validator)?.let { addWarningMessage(it) }
|
||||
checkIfWarningNeeded(card)?.let { warning -> addWarningMessage(warning) }
|
||||
}
|
||||
if (card.getType() == CardType.Release) {
|
||||
if (globalState.scanNoteResponse.verifyResponse?.verificationState ==
|
||||
|
|
@ -82,12 +83,14 @@ class WarningsMiddleware {
|
|||
}
|
||||
|
||||
private fun checkIfWarningNeeded(
|
||||
card: Card, signatureCountValidator: SignatureCountValidator? = null,
|
||||
card: Card
|
||||
): WarningMessage? {
|
||||
if (card.isTwinCard() || card.isMultiwalletAllowed) return null
|
||||
if (card.isTwinCard()) return null
|
||||
|
||||
return if (signatureCountValidator == null) {
|
||||
if (card.walletSignedHashes ?: 0 > 0) {
|
||||
val validator = store.state.walletState.walletManagers.firstOrNull()
|
||||
as? SignatureCountValidator
|
||||
return if (validator == null || card.isMultiwalletAllowed) {
|
||||
if (card.hasSignedHashes()) {
|
||||
WarningMessagesManager.alreadySignedHashesWarning()
|
||||
} else {
|
||||
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
|
||||
|
|
@ -108,10 +111,11 @@ class WarningsMiddleware {
|
|||
|
||||
if (card.isTwinCard() || card.isMultiwalletAllowed) return
|
||||
|
||||
val validator = store.state.globalState.scanNoteResponse?.walletManager
|
||||
val validator = store.state.walletState.walletManagers.firstOrNull()
|
||||
as? SignatureCountValidator
|
||||
scope.launch {
|
||||
val result = validator?.validateSignatureCount(card.walletSignedHashes ?: 0)
|
||||
val signedHashes = card.getSingleWallet()?.signedHashes ?: 0
|
||||
val result = validator?.validateSignatureCount(signedHashes)
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
SimpleResult.Success -> {
|
||||
|
|
@ -121,7 +125,7 @@ class WarningsMiddleware {
|
|||
is SimpleResult.Failure ->
|
||||
if (result.error is BlockchainSdkError.SignatureCountNotMatched) {
|
||||
addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true)
|
||||
} else if (card.walletSignedHashes ?: 0 > 0) {
|
||||
} else if (signedHashes > 0) {
|
||||
addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,28 +34,26 @@ class MultiWalletView : WalletView {
|
|||
override fun changeWalletView(fragment: WalletFragment) {
|
||||
setFragment(fragment)
|
||||
onViewCreated()
|
||||
showMultiWalletView()
|
||||
setupButtons()
|
||||
showMultiWalletView(fragment)
|
||||
setupButtons(fragment)
|
||||
}
|
||||
|
||||
|
||||
private fun showMultiWalletView() {
|
||||
val fragment = fragment ?: return
|
||||
fragment.tv_twin_card_number.hide()
|
||||
fragment.iv_twin_card.hide()
|
||||
fragment.rv_pending_transaction.hide()
|
||||
fragment.l_card_balance.hide()
|
||||
fragment.l_address.hide()
|
||||
fragment.l_buttons_short.hide()
|
||||
fragment.l_buttons_long.hide()
|
||||
fragment.btn_scan_multiwallet?.show()
|
||||
fragment.rv_multiwallet.show()
|
||||
fragment.btn_add_token.show()
|
||||
private fun showMultiWalletView(fragment: WalletFragment) = with(fragment) {
|
||||
tv_twin_card_number.hide()
|
||||
iv_twin_card.hide()
|
||||
rv_pending_transaction.hide()
|
||||
l_card_balance.hide()
|
||||
l_address.hide()
|
||||
l_buttons_short.hide()
|
||||
l_buttons_long.hide()
|
||||
btn_scan_multiwallet?.show()
|
||||
rv_multiwallet.show()
|
||||
btn_add_token.show()
|
||||
}
|
||||
|
||||
private fun setupButtons() {
|
||||
val fragment = fragment ?: return
|
||||
fragment.btn_scan_multiwallet?.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
private fun setupButtons(fragment: WalletFragment) = with(fragment) {
|
||||
btn_scan_multiwallet?.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
}
|
||||
|
||||
override fun setFragment(fragment: WalletFragment) {
|
||||
|
|
@ -114,22 +112,22 @@ class MultiWalletView : WalletView {
|
|||
|
||||
private fun showErrorState(
|
||||
fragment: WalletFragment, errorTitle: CharSequence, errorDescription: CharSequence,
|
||||
) {
|
||||
fragment.l_card_balance.show()
|
||||
fragment.l_balance.hide()
|
||||
fragment.l_balance_error.show()
|
||||
fragment.rv_multiwallet.hide()
|
||||
fragment.btn_add_token.hide()
|
||||
fragment.tv_error_title.text = errorTitle
|
||||
fragment.tv_error_descriptions.text = errorDescription
|
||||
) = with(fragment) {
|
||||
l_card_balance.show()
|
||||
l_balance.hide()
|
||||
l_balance_error.show()
|
||||
rv_multiwallet.hide()
|
||||
btn_add_token.hide()
|
||||
tv_error_title.text = errorTitle
|
||||
tv_error_descriptions.text = errorDescription
|
||||
}
|
||||
|
||||
private fun configureButtonsForEmptyWalletState(fragment: WalletFragment) {
|
||||
fragment.btn_scan_multiwallet.hide()
|
||||
fragment.l_buttons_long.show()
|
||||
fragment.btn_scan_long.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
fragment.btn_confirm_long.setOnClickListener { store.dispatch(WalletAction.CreateWallet) }
|
||||
fragment.btn_confirm_long.text = fragment.getText(R.string.wallet_button_create_wallet)
|
||||
private fun configureButtonsForEmptyWalletState(fragment: WalletFragment) = with(fragment) {
|
||||
btn_scan_multiwallet.hide()
|
||||
l_buttons_long.show()
|
||||
btn_scan_long.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
btn_confirm_long.setOnClickListener { store.dispatch(WalletAction.CreateWallet) }
|
||||
btn_confirm_long.text = fragment.getText(R.string.wallet_button_create_wallet)
|
||||
}
|
||||
|
||||
private fun handleDialogs(walletDialog: StateDialog?) {
|
||||
|
|
|
|||
|
|
@ -44,17 +44,16 @@ class SingleWalletView : WalletView {
|
|||
override fun changeWalletView(fragment: WalletFragment) {
|
||||
setFragment(fragment)
|
||||
onViewCreated()
|
||||
showSingleWalletView()
|
||||
showSingleWalletView(fragment)
|
||||
}
|
||||
|
||||
private fun showSingleWalletView() {
|
||||
val fragment = fragment ?: return
|
||||
fragment.rv_multiwallet.hide()
|
||||
fragment.btn_add_token.hide()
|
||||
fragment.btn_scan_multiwallet?.hide()
|
||||
fragment.rv_pending_transaction.hide()
|
||||
fragment.l_card_balance.show()
|
||||
fragment.l_address.show()
|
||||
private fun showSingleWalletView(fragment: WalletFragment) = with(fragment) {
|
||||
rv_multiwallet.hide()
|
||||
btn_add_token.hide()
|
||||
btn_scan_multiwallet?.hide()
|
||||
rv_pending_transaction.hide()
|
||||
l_card_balance.show()
|
||||
l_address.show()
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
|
|
@ -70,13 +69,15 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
|
||||
override fun onNewState(state: WalletState) {
|
||||
setupTwinCards(state.twinCardsState)
|
||||
val fragment = fragment ?: return
|
||||
state.primaryWallet ?: return
|
||||
setupButtons(state.primaryWallet, state.twinCardsState != null)
|
||||
setupAddressCard(state.primaryWallet)
|
||||
|
||||
setupTwinCards(state.twinCardsState, fragment)
|
||||
setupButtons(state.primaryWallet, state.twinCardsState != null, fragment)
|
||||
setupAddressCard(state.primaryWallet, fragment)
|
||||
showPendingTransactionsIfPresent(state.primaryWallet.pendingTransactions)
|
||||
setupBalance(state, state.primaryWallet)
|
||||
handleDialogs(state.walletDialog)
|
||||
handleDialogs(state.walletDialog, fragment)
|
||||
}
|
||||
|
||||
private fun showPendingTransactionsIfPresent(pendingTransactions: List<PendingTransaction>) {
|
||||
|
|
@ -92,43 +93,45 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupTwinCards(twinCardsState: TwinCardsState?) {
|
||||
fragment?.apply {
|
||||
twinCardsState?.cardNumber?.let { cardNumber ->
|
||||
this.tv_twin_card_number.show()
|
||||
this.iv_twin_card.show()
|
||||
val number = when (cardNumber) {
|
||||
TwinCardNumber.First -> "1"
|
||||
TwinCardNumber.Second -> "2"
|
||||
}
|
||||
this.tv_twin_card_number.text =
|
||||
this.getString(R.string.wallet_twins_chip_format, number)
|
||||
}
|
||||
if (twinCardsState?.cardNumber == null) {
|
||||
this.tv_twin_card_number.hide()
|
||||
this.iv_twin_card.hide()
|
||||
}
|
||||
if (twinCardsState?.showTwinOnboarding == true) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding))
|
||||
private fun setupTwinCards(
|
||||
twinCardsState: TwinCardsState?, fragment: WalletFragment
|
||||
) = with(fragment) {
|
||||
twinCardsState?.cardNumber?.let { cardNumber ->
|
||||
tv_twin_card_number.show()
|
||||
iv_twin_card.show()
|
||||
val number = when (cardNumber) {
|
||||
TwinCardNumber.First -> "1"
|
||||
TwinCardNumber.Second -> "2"
|
||||
}
|
||||
tv_twin_card_number.text =
|
||||
this.getString(R.string.wallet_twins_chip_format, number)
|
||||
}
|
||||
if (twinCardsState?.cardNumber == null) {
|
||||
tv_twin_card_number.hide()
|
||||
iv_twin_card.hide()
|
||||
}
|
||||
if (twinCardsState?.showTwinOnboarding == true) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun setupButtons(state: WalletData, isTwinsWallet: Boolean) {
|
||||
val fragment = fragment ?: return
|
||||
private fun setupButtons(
|
||||
state: WalletData, isTwinsWallet: Boolean, fragment: WalletFragment
|
||||
) = with(fragment){
|
||||
|
||||
setupButtonsType(state, fragment)
|
||||
|
||||
val btnConfirm = if (state.topUpState.allowed) {
|
||||
fragment.btn_confirm_short
|
||||
btn_confirm_short
|
||||
} else {
|
||||
fragment.btn_confirm_long
|
||||
btn_confirm_long
|
||||
}
|
||||
val btnScan = if (state.topUpState.allowed) {
|
||||
fragment.btn_scan_short
|
||||
btn_scan_short
|
||||
} else {
|
||||
fragment.btn_scan_long
|
||||
btn_scan_long
|
||||
}
|
||||
|
||||
setupConfirmButton(state, btnConfirm, fragment, isTwinsWallet)
|
||||
|
|
@ -137,27 +140,27 @@ class SingleWalletView : WalletView {
|
|||
store.dispatch(WalletAction.Scan)
|
||||
}
|
||||
|
||||
fragment.btn_copy.setOnClickListener {
|
||||
btn_copy.setOnClickListener {
|
||||
state.walletAddresses?.selectedAddress?.address?.let { addressString ->
|
||||
store.dispatch(WalletAction.CopyAddress(addressString, fragment.requireContext()))
|
||||
}
|
||||
}
|
||||
fragment.btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) }
|
||||
btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) }
|
||||
|
||||
fragment.btn_top_up.setOnClickListener {
|
||||
btn_top_up.setOnClickListener {
|
||||
store.dispatch(
|
||||
WalletAction.TopUpAction.TopUp(fragment.requireContext(), R.color.backgroundLightGray)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupButtonsType(state: WalletData, fragment: WalletFragment) {
|
||||
private fun setupButtonsType(state: WalletData, fragment: WalletFragment) = with(fragment) {
|
||||
if (state.topUpState.allowed) {
|
||||
fragment.l_buttons_long.hide()
|
||||
fragment.l_buttons_short.show()
|
||||
l_buttons_long.hide()
|
||||
l_buttons_short.show()
|
||||
} else {
|
||||
fragment.l_buttons_long.show()
|
||||
fragment.l_buttons_short.hide()
|
||||
l_buttons_long.show()
|
||||
l_buttons_short.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,39 +188,37 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
|
||||
|
||||
private fun setupAddressCard(state: WalletData) {
|
||||
val fragment = fragment ?: return
|
||||
private fun setupAddressCard(state: WalletData, fragment: WalletFragment) = with(fragment) {
|
||||
if (state.walletAddresses != null && state.blockchain != null) {
|
||||
fragment.l_address?.show()
|
||||
l_address?.show()
|
||||
if (state.shouldShowMultipleAddress()) {
|
||||
(fragment.l_address as? ViewGroup)?.beginDelayedTransition()
|
||||
fragment.chip_group_address_type.show()
|
||||
fragment.chip_group_address_type.fitChipsByGroupWidth()
|
||||
(l_address as? ViewGroup)?.beginDelayedTransition()
|
||||
chip_group_address_type.show()
|
||||
chip_group_address_type.fitChipsByGroupWidth()
|
||||
|
||||
val checkedId = MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type)
|
||||
if (checkedId != View.NO_ID) fragment.chip_group_address_type.check(checkedId)
|
||||
if (checkedId != View.NO_ID) chip_group_address_type.check(checkedId)
|
||||
|
||||
fragment.chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
|
||||
chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
|
||||
if (checkedId == -1) return@setOnCheckedChangeListener
|
||||
val type = MultipleAddressUiHelper.idToType(checkedId, state.blockchain)
|
||||
type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) }
|
||||
}
|
||||
} else {
|
||||
fragment.chip_group_address_type.hide()
|
||||
chip_group_address_type.hide()
|
||||
}
|
||||
fragment.tv_address.text = state.walletAddresses.selectedAddress.address
|
||||
fragment.tv_explore?.setOnClickListener {
|
||||
tv_address.text = state.walletAddresses.selectedAddress.address
|
||||
tv_explore?.setOnClickListener {
|
||||
store.dispatch(WalletAction.ExploreAddress(
|
||||
state.walletAddresses.selectedAddress.exploreUrl,
|
||||
fragment.requireContext()))
|
||||
}
|
||||
} else {
|
||||
fragment.l_address?.hide()
|
||||
l_address?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDialogs(walletDialog: StateDialog?) {
|
||||
val fragment = fragment ?: return
|
||||
private fun handleDialogs(walletDialog: StateDialog?, fragment: WalletFragment) {
|
||||
val context = fragment.context ?: return
|
||||
when (walletDialog) {
|
||||
is WalletDialog.QrDialog -> {
|
||||
|
|
|
|||
|
|
@ -90,28 +90,6 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/tv_card_id"
|
||||
tools:text="Tangem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_signed_hashes_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:text="@string/details_row_title_signed_hashes"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_issuer_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_signed_hashes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/darkGray1"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_issuer"
|
||||
tools:text="48 hashes" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_disclaimer"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -124,7 +102,7 @@
|
|||
android:textSize="16sp"
|
||||
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes_title" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_issuer_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_card_tou"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue