Updated on 2026-08-14

This commit is contained in:
Tangem 2021-12-15 18:51:35 +00:00
commit 3e1ebc974b
18 changed files with 241 additions and 151 deletions

View file

@ -4,5 +4,6 @@ package com.tangem.tap.domain
[REDACTED_AUTHOR]
*/
enum class ProductType {
Note, Wallet, Twins, Other
Note, Twins, Wallet
}

View file

@ -45,7 +45,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
analyticsHandler.triggerEvent(AnalyticsEvent.READY_TO_SCAN, null)
val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header))
return runTaskAsyncReturnOnMain(ScanProductTask(null, currenciesRepository, shouldDeriveWC), null, message)
return runTaskAsyncReturnOnMain(ScanProductTask(null, currenciesRepository), null, message)
.also { sendScanFailuresToAnalytics(analyticsHandler, it) }
}

View file

@ -35,8 +35,7 @@ object TapWorkarounds {
@Deprecated("Use ScanResponse.isTangemNote")
fun isTangemNote(card: Card): Boolean = tangemNoteBatches.contains(card.batchId)
@Deprecated("Use ScanResponse.isTangemWallet")
fun isTangemWallet(card: Card): Boolean = tangemWalletBatches.contains(card.batchId)
fun isTangemWalletBatch(card: Card): Boolean = tangemWalletBatches.contains(card.batchId)
fun getTangemNoteBlockchain(card: Card): Blockchain? = tangemNoteBatches[card.batchId]

View file

@ -2,7 +2,6 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.common.card.EllipticCurve
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemSdkError
@ -45,8 +44,7 @@ class CreateProductWalletTask(
val commandProcessor = when (type) {
ProductType.Note -> CreateWalletTangemNote()
ProductType.Twins -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
ProductType.Wallet -> CreateWalletTangemWallet()
else -> CreateWalletOtherCards()
else -> CreateWalletTangemWallet()
}
commandProcessor.proceed(card, session) {
when (it) {
@ -106,13 +104,27 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
val supportedCurves = setOf(EllipticCurve.Secp256k1, EllipticCurve.Ed25519)
val curves = card.getCurvesForNonCreatedWallets().intersect(supportedCurves).toList()
val curves = card.getCurvesForNonCreatedWallets()
CreateWalletsTask(curves).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
createWalletResponse = result.data.createWalletResponses[0]
linkPrimaryCard(card, session, callback)
when {
card.settings.isBackupAllowed -> {
linkPrimaryCard(session, callback)
}
card.settings.isHDWalletAllowed -> {
deriveKeys(session, callback)
}
else -> {
callback(
CompletionResult.Success(
CreateProductWalletTaskResponse(card = session.environment.card!!)
)
)
}
}
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
@ -120,7 +132,6 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
}
private fun linkPrimaryCard(
card: Card,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
@ -128,7 +139,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
when (result) {
is CompletionResult.Success -> {
primaryCard = result.data
deriveKeys(card, session, callback)
deriveKeys(session, callback)
}
is CompletionResult.Failure -> {
callback(CompletionResult.Failure(result.error))
@ -138,7 +149,6 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
}
private fun deriveKeys(
card: Card,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
@ -149,42 +159,34 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
return
}
if (derivationPaths.isNullOrEmpty()) {
callback(
CompletionResult.Success(
CreateProductWalletTaskResponse(
card = session.environment.card!!, primaryCard = primaryCard
)
)
)
return
}
DeriveWalletPublicKeysTask(response.wallet.publicKey, derivationPaths)
.run(session) { result ->
when (result) {
is CompletionResult.Success -> {
val derivedKeys = mapOf(response.wallet.publicKey.toMapKey() to result.data)
callback(CompletionResult.Success(CreateProductWalletTaskResponse(
card = session.environment.card!!,
derivedKeys = derivedKeys,
primaryCard = primaryCard
)))
callback(
CompletionResult.Success(
CreateProductWalletTaskResponse(
card = session.environment.card!!,
derivedKeys = derivedKeys,
primaryCard = primaryCard
)
)
)
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
}
private class CreateWalletOtherCards : ProductCommandProcessor<CreateWalletResponse> {
override fun proceed(
card: Card,
session: CardSession,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
) {
val firmwareVersion = card.firmwareVersion
val task = if (firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
CreateWalletsTask(listOf(card.supportedCurves.first()))
} else {
CreateWalletsTask(card.getCurvesForNonCreatedWallets())
}
task.run(session) { result ->
when (result) {
is CompletionResult.Success -> callback(CompletionResult.Success(result.data.createWalletResponses[0]))
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
}

View file

@ -47,7 +47,8 @@ data class ScanResponse(
) : CommandResponse {
fun getBlockchain(): Blockchain {
if (productType == ProductType.Note) return getTangemNoteBlockchain(card) ?: return Blockchain.Unknown
if (productType == ProductType.Note) return getTangemNoteBlockchain(card)
?: return Blockchain.Unknown
val blockchainName: String = walletData?.blockchain ?: return Blockchain.Unknown
return Blockchain.fromId(blockchainName)
}
@ -66,17 +67,19 @@ data class ScanResponse(
fun isTangemNote(): Boolean = productType == ProductType.Note
fun isTangemWallet(): Boolean = productType == ProductType.Wallet
fun isTangemTwins(): Boolean = productType == ProductType.Twins
fun isTangemOtherCards(): Boolean = productType == ProductType.Other
fun twinsIsTwinned(): Boolean = card.isTangemTwins() && walletData != null && secondTwinPublicKey != null
fun supportsHdWallet(): Boolean = card.settings.isHDWalletAllowed
fun supportsBackup(): Boolean = card.settings.isBackupAllowed
fun twinsIsTwinned(): Boolean =
card.isTangemTwins() && walletData != null && secondTwinPublicKey != null
}
typealias KeyWalletPublicKey = ByteArrayKey
class ScanProductTask(
val card: Card? = null,
private val currenciesRepository: CurrenciesRepository?,
private val shouldDeriveWC: Boolean
private val currenciesRepository: CurrenciesRepository?
) : CardSessionRunnable<ScanResponse> {
override fun run(
@ -97,15 +100,22 @@ class ScanProductTask(
val commandProcessor = when {
TapWorkarounds.isTangemNote(card) -> ScanNoteProcessor()
card.isTangemTwins() -> ScanTwinProcessor()
TapWorkarounds.isTangemWallet(card) -> ScanWalletProcessor(currenciesRepository, shouldDeriveWC)
else -> ScanOtherCardsProcessor()
else -> ScanWalletProcessor(currenciesRepository)
}
commandProcessor.proceed(card, session) { processorResult ->
when (processorResult) {
is CompletionResult.Success -> ScanTask().run(session) { scanTaskResult ->
when (scanTaskResult) {
is CompletionResult.Success -> callback(CompletionResult.Success(processorResult.data))
is CompletionResult.Failure -> callback(CompletionResult.Failure(scanTaskResult.error))
is CompletionResult.Success -> callback(
CompletionResult.Success(
processorResult.data
)
)
is CompletionResult.Failure -> callback(
CompletionResult.Failure(
scanTaskResult.error
)
)
}
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(processorResult.error))
@ -129,13 +139,20 @@ private class ScanNoteProcessor : ProductCommandProcessor<ScanResponse> {
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit
) {
callback(CompletionResult.Success(ScanResponse(card, ProductType.Note, session.environment.walletData)))
callback(
CompletionResult.Success(
ScanResponse(
card,
ProductType.Note,
session.environment.walletData
)
)
)
}
}
private class ScanWalletProcessor(
private val currenciesRepository: CurrenciesRepository?,
private val shouldDeriveWC: Boolean
private val currenciesRepository: CurrenciesRepository?
) : ProductCommandProcessor<ScanResponse> {
var primaryCard: PrimaryCard? = null
@ -145,9 +162,60 @@ private class ScanWalletProcessor(
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit
) {
val activationIsFinished = preferencesStorage.usedCardsPrefStorage.isActivationFinished(card.cardId)
createMissingWalletsIfNeeded(card, session, callback)
}
if (card.backupStatus?.isActive != true && !activationIsFinished && card.wallets.isNotEmpty()) {
private fun createMissingWalletsIfNeeded(
card: Card,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit
) {
if (card.wallets.isEmpty() || card.firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
startLinkingForBackupIfNeeded(card, session, callback)
return
}
val curvesToCreate = card.getCurvesForNonCreatedWallets()
if (curvesToCreate.isEmpty()) {
startLinkingForBackupIfNeeded(card, session, callback)
return
}
CreateWalletsTask(curvesToCreate).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
PreflightReadTask(
PreflightReadMode.FullCardRead,
card.cardId
).run(session) { readResult ->
when (readResult) {
is CompletionResult.Success -> {
startLinkingForBackupIfNeeded(card, session, callback)
}
is CompletionResult.Failure -> callback(
CompletionResult.Failure(
readResult.error
)
)
}
}
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
private fun startLinkingForBackupIfNeeded(
card: Card,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit
) {
val activationIsFinished =
preferencesStorage.usedCardsPrefStorage.isActivationFinished(card.cardId)
if (card.backupStatus == Card.BackupStatus.NoBackup &&
!activationIsFinished && card.wallets.isNotEmpty()
) {
StartPrimaryCardLinkingTask().run(session) { linkingResult ->
when (linkingResult) {
is CompletionResult.Success -> {
@ -162,7 +230,6 @@ private class ScanWalletProcessor(
} else {
deriveKeysIfNeeded(card, session, callback)
}
}
private fun deriveKeysIfNeeded(
@ -174,12 +241,16 @@ private class ScanWalletProcessor(
val wallet = card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 }
if (derivationPaths.isNullOrEmpty() || wallet == null || wallet.chainCode == null) {
callback(CompletionResult.Success(ScanResponse(
card = card,
productType = ProductType.Wallet,
walletData = session.environment.walletData,
primaryCard = primaryCard
)))
callback(
CompletionResult.Success(
ScanResponse(
card = card,
productType = ProductType.Wallet,
walletData = session.environment.walletData,
primaryCard = primaryCard
)
)
)
return
}
@ -213,8 +284,14 @@ private class ScanWalletProcessor(
(cardCurrencies.blockchains + tokenBlockchains).toMutableList()
}
if (shouldDeriveWC) {
blockchainsToDerive.addAll(listOf(Blockchain.Ethereum, Blockchain.Binance, Blockchain.EthereumTestnet))
if (card.settings.isHDWalletAllowed) {
blockchainsToDerive.addAll(
listOf(
Blockchain.Ethereum,
Blockchain.Binance,
Blockchain.EthereumTestnet
)
)
}
return blockchainsToDerive.toSet()
@ -234,17 +311,39 @@ private class ScanTwinProcessor : ProductCommandProcessor<ScanResponse> {
is CompletionResult.Success -> {
val publicKey = card.getSingleWallet()?.publicKey
if (publicKey == null) {
callback(CompletionResult.Success(ScanResponse(card, ProductType.Twins, null)))
callback(
CompletionResult.Success(
ScanResponse(
card,
ProductType.Twins,
null
)
)
)
return@run
}
val verified = TwinsHelper.verifyTwinPublicKey(readDataResult.data.issuerData, publicKey)
val verified =
TwinsHelper.verifyTwinPublicKey(readDataResult.data.issuerData, publicKey)
if (verified) {
val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65)
val walletData = session.environment.walletData
val response = ScanResponse(card, ProductType.Twins, walletData, twinPublicKey.toHexString())
val response = ScanResponse(
card,
ProductType.Twins,
walletData,
twinPublicKey.toHexString()
)
callback(CompletionResult.Success(response))
} else {
callback(CompletionResult.Success(ScanResponse(card, ProductType.Twins, null)))
callback(
CompletionResult.Success(
ScanResponse(
card,
ProductType.Twins,
null
)
)
)
}
}
is CompletionResult.Failure ->
@ -255,43 +354,9 @@ private class ScanTwinProcessor : ProductCommandProcessor<ScanResponse> {
}
private class ScanOtherCardsProcessor : ProductCommandProcessor<ScanResponse> {
override fun proceed(card: Card, session: CardSession, callback: (result: CompletionResult<ScanResponse>) -> Unit) {
val walletData = session.environment.walletData
if (card.wallets.isEmpty() || card.firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData)))
return
}
val curvesToCreate = card.getCurvesForNonCreatedWallets()
if (curvesToCreate.isEmpty()) {
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData)))
return
}
CreateWalletsTask(curvesToCreate).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
PreflightReadTask(PreflightReadMode.FullCardRead, card.cardId).run(session) { readResult ->
when (readResult) {
is CompletionResult.Success -> {
val response = ScanResponse(readResult.data, ProductType.Other, walletData)
callback(CompletionResult.Success(response))
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(readResult.error))
}
}
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
}
fun Card.getCurvesForNonCreatedWallets(): List<EllipticCurve> {
val curvesPresent = wallets.map { it.curve }
val curvesForNonCreatedWallets = supportedCurves.subtract(curvesPresent)
val curvesPresent = wallets.map { it.curve }.toSet()
val curvesForNonCreatedWallets = supportedCurves
.subtract(curvesPresent + EllipticCurve.Secp256r1)
return curvesForNonCreatedWallets.toList()
}

View file

@ -23,7 +23,8 @@ class FinalizeTwinTask(
PreflightReadTask(PreflightReadMode.FullCardRead).run(session) { readResult ->
when (readResult) {
is CompletionResult.Success ->
ScanProductTask(readResult.data, null, false).run(session, callback)
ScanProductTask(readResult.data, null)
.run(session, callback)
is CompletionResult.Failure ->
callback(CompletionResult.Failure(readResult.error))
}

View file

@ -51,7 +51,7 @@ private fun handlePrepareScreen(
cardInfo = action.scanResponse.card.toCardInfo(),
appCurrencyState = AppCurrencyState(action.fiatCurrencyName),
cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card),
createBackupAllowed = action.scanResponse.isTangemWallet() && !backupIsActive,
createBackupAllowed = action.scanResponse.card.backupStatus == Card.BackupStatus.NoBackup,
)
}
@ -65,7 +65,7 @@ private fun handleEraseWallet(
val notAllowedByAnyWallet = card?.wallets?.any { it.settings.isPermanent } ?: false
val notAllowedByCard = notAllowedByAnyWallet ||
(card?.isWalletDataSupported == true &&
(!state.scanResponse.isTangemNote() && !state.scanResponse.isTangemWallet()))
(!state.scanResponse.isTangemNote() && !state.scanResponse.supportsBackup()))
val notEmpty = state.wallets.any {
it.hasPendingTransactions() || it.amounts.toSendableAmounts().isNotEmpty()
@ -139,7 +139,7 @@ private fun handleSecurityAction(
state.scanResponse?.isTangemNote() == true -> {
EnumSet.of(SecurityOption.LongTap)
}
state.scanResponse?.isTangemWallet() == true -> {
state.scanResponse?.supportsBackup() == true -> {
EnumSet.of(state.securityScreenState?.currentOption)
}
else -> prepareAllowedSecurityOptions(

View file

@ -218,7 +218,6 @@ interface EmailData {
fun joinTogether(infoHolder: AdditionalEmailInfo): String {
return "$mainMessage\n\n\n\n" +
"Following information is optional. You can erase it if you dont want to share it.\n" +
createOptionalMessage(infoHolder)
}
}

View file

@ -32,9 +32,12 @@ class OnboardingHelper {
fun whereToNavigate(scanResponse: ScanResponse): AppScreen {
return when (scanResponse.productType) {
ProductType.Note -> AppScreen.OnboardingNote
ProductType.Wallet -> AppScreen.OnboardingWallet
ProductType.Wallet -> if (scanResponse.card.settings.isBackupAllowed) {
AppScreen.OnboardingWallet
} else {
AppScreen.OnboardingOther
}
ProductType.Twins -> AppScreen.OnboardingTwins
ProductType.Other -> AppScreen.OnboardingOther
}
}
}

View file

@ -22,7 +22,7 @@ sealed class OnboardingWalletAction : Action {
sealed class BackupAction : Action {
object DetermineBackupStep : BackupAction()
object IntroduceBackup : BackupAction()
data class IntroduceBackup(val buyCardsUrl: String? = null) : BackupAction()
object StartBackup : BackupAction()
object DismissBackup : BackupAction()

View file

@ -110,7 +110,14 @@ private fun handleWalletAction(action: Action) {
BackupService.State.FinalizingPrimaryCard -> BackupAction.PrepareToWritePrimaryCard
is BackupService.State.FinalizingBackupCard ->
BackupAction.PrepareToWriteBackupCard(backupState.index)
else -> BackupAction.IntroduceBackup
else -> {
val url = if (card?.issuer?.name?.lowercase()?.contains("tangem") == true) {
BUY_WALLET_URL
} else {
null
}
BackupAction.IntroduceBackup(url)
}
}
store.dispatch(newAction)
}

View file

@ -39,9 +39,10 @@ class BackupReducer {
): BackupState {
return when (action) {
BackupAction.IntroduceBackup -> BackupState(
is BackupAction.IntroduceBackup -> BackupState(
backupStep = BackupStep.InitBackup,
canSkipBackup = state.canSkipBackup
canSkipBackup = state.canSkipBackup,
buyAdditionalCardsUrl = action.buyCardsUrl
)
BackupAction.StartAddingPrimaryCard -> state.copy(backupStep = BackupStep.ScanOriginCard)

View file

@ -52,7 +52,8 @@ data class BackupState(
val accessCodeError: AccessCodeError? = null,
val backupStep: BackupStep = BackupStep.InitBackup,
val maxBackupCards: Int = 2,
val canSkipBackup: Boolean = true
val canSkipBackup: Boolean = true,
val buyAdditionalCardsUrl: String? = null
)
enum class AccessCodeError {

View file

@ -15,7 +15,13 @@ class BackupCardsWidget(
val getTopOfAnchorViewForActivateState: () -> Float,
) {
var currentState: WidgetState? = null
fun toWelcome(animate: Boolean = true, onEnd: () -> Unit = {}) {
if (currentState == WidgetState.WELCOME) return
currentState = WidgetState.WELCOME
val animator = createAnimator(animate, onEnd)
animator.playTogether(
createAnimator(BackupCardType.ORIGIN, createWelcomeProperties(BackupCardType.ORIGIN)),
@ -26,6 +32,10 @@ class BackupCardsWidget(
}
fun toFolded(animate: Boolean = true, onEnd: () -> Unit = {}) {
if (currentState == WidgetState.FOLDED) return
currentState = WidgetState.FOLDED
val animator = createAnimator(animate, onEnd)
animator.playTogether(
createAnimator(BackupCardType.ORIGIN, createLeapfrogProperties(BackupCardType.ORIGIN)),
@ -36,6 +46,10 @@ class BackupCardsWidget(
}
fun toFan(animate: Boolean = true, onEnd: () -> Unit = {}) {
if (currentState == WidgetState.FAN) return
currentState = WidgetState.FAN
val animator = createAnimator(animate, onEnd)
animator.playTogether(
createAnimator(BackupCardType.ORIGIN, createFanProperties(BackupCardType.ORIGIN)),
@ -46,6 +60,8 @@ class BackupCardsWidget(
}
fun toLeapfrog(animate: Boolean = true, onEnd: () -> Unit = {}) {
currentState = WidgetState.LEAPFROG
val animator = createAnimator(animate, onEnd)
animator.playTogether(
createAnimator(BackupCardType.ORIGIN, createLeapfrogProperties(BackupCardType.ORIGIN)),
@ -60,15 +76,6 @@ class BackupCardsWidget(
animator.start()
}
}
//
// fun toActivate(animate: Boolean = true, onEnd: () -> Unit = {}) {
// val animator = createAnimator(animate, onEnd)
// animator.playTogether(
// createAnimator(TwinCardNumber.First, createActivateProperties(TwinCardNumber.First)),
// createAnimator(TwinCardNumber.Second, createActivateProperties(TwinCardNumber.Second))
// )
// animator.start()
// }
private fun createAnimator(animate: Boolean, onEnd: () -> Unit): AnimatorSet {
return AnimatorSet().apply {
@ -196,6 +203,8 @@ class BackupCardsWidget(
fun getSecondBackupCardView(): ImageView {
return getLeapViewByCardNumber(BackupCardType.SECOND_BACKUP).view as ImageView
}
enum class WidgetState { WELCOME, FOLDED, FAN, LEAPFROG }
}

View file

@ -148,19 +148,10 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
}
private fun showScanOriginCard(state: BackupState) {
toolbar.title = getText(R.string.onboarding_navbar_title_creating_backup)
prepareBackupView()
cardsWidget.toFolded()
tv_header.show()
tv_body.show()
view_pager_backup_info.hide()
tab_layout_backup_info.hide()
imv_first_backup_card.show()
imv_second_backup_card.show()
tv_header.text = getText(R.string.onboarding_title_scan_origin_card)
tv_body.text = getString(
R.string.onboarding_subtitle_scan_origin_card,
@ -171,9 +162,20 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
btn_main_action.setOnClickListener { store.dispatch(BackupAction.ScanPrimaryCard) }
}
private fun showAddBackupCards(state: BackupState) {
private fun prepareBackupView() {
toolbar.title = getText(R.string.onboarding_navbar_title_creating_backup)
tv_header.show()
tv_body.show()
view_pager_backup_info.hide()
tab_layout_backup_info.hide()
imv_first_backup_card.show()
imv_second_backup_card.show()
}
private fun showAddBackupCards(state: BackupState) {
prepareBackupView()
accessCodeDialog?.dismiss()
accessCodeDialog = null
@ -190,11 +192,12 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
when (state.backupCardsNumber) {
0 -> {
cardsWidget.toFan()
cardsWidget.toFan() {
cardsWidget.getFirstBackupCardView().animate().alpha(0.6f).setDuration(200)
cardsWidget.getSecondBackupCardView().animate().alpha(0.2f).setDuration(200)
}
tv_header.text = getText(R.string.onboarding_title_no_backup_cards)
tv_body.text = getText(R.string.onboarding_subtitle_no_backup_cards)
cardsWidget.getFirstBackupCardView().alpha = 0.6f
cardsWidget.getSecondBackupCardView().alpha = 0.2f
}
1 -> {
tv_header.text = getText(R.string.onboarding_title_one_backup_card)
@ -283,10 +286,6 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
cardsWidget.toLeapfrog()
// imv_front_card.alpha = 1f
// imv_first_backup_card.alpha = 1f
// imv_second_backup_card.alpha = 1f
btn_alternative_action.hide()
}
@ -373,9 +372,12 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.shop, menu)
val backupStep = store.state.onboardingWalletState.backupState.backupStep
val backupState = store.state.onboardingWalletState.backupState
val backupStep = backupState.backupStep
val shopMenuShouldBeVisible =
backupStep == BackupStep.ScanOriginCard || backupStep == BackupStep.AddBackupCards
(backupStep == BackupStep.ScanOriginCard || backupStep == BackupStep.AddBackupCards) &&
backupState.buyAdditionalCardsUrl != null
menu.getItem(0).isVisible = shopMenuShouldBeVisible
}

View file

@ -46,7 +46,7 @@ class TokensMiddleware {
isTestNet = isTestcard
)
val currencies = CurrencyListItem.createListOfCurrencies(blockchains, tokens).toMutableList()
if (scanResponse.isTangemWallet()) {
if (scanResponse.supportsHdWallet()) {
currencies.forEach {
when (it) {
is CurrencyListItem.TitleListItem -> {
@ -81,7 +81,7 @@ class TokensMiddleware {
.map { it.token }
if (blockchains.isEmpty() && tokens.isEmpty()) return
if (scanResponse.isTangemWallet()) {
if (scanResponse.supportsHdWallet()) {
deriveMissingBlockchains(scanResponse, blockchains, tokens)
} else {
submitAdd(blockchains, tokens)

View file

@ -85,7 +85,7 @@ class MultiWalletMiddleware {
}
is WalletAction.MultiWallet.FindBlockchainsInUse -> {
val scanResponse = globalState.scanResponse ?: return
if (scanResponse.isTangemWallet()) return
if (scanResponse.supportsHdWallet()) return
val cardFirmware = scanResponse.card.firmwareVersion
val blockchains = currenciesRepository.getBlockchains(cardFirmware)
@ -125,7 +125,7 @@ class MultiWalletMiddleware {
}
is WalletAction.MultiWallet.FindTokensInUse -> {
val scanResponse = globalState.scanResponse ?: return
if (scanResponse.isTangemWallet()) return
if (scanResponse.supportsHdWallet()) return
val walletFactory = tapWalletManager.walletManagerFactory
val card = scanResponse.card

View file

@ -109,7 +109,7 @@
<string name="alert_old_device_this_card">You may experience NFC problems with some iPhone 7/7+ during the extraction</string>
<string name="alert_card_signed_transactions">This card has been already topped up and signed transactions in the past. Consider immediate withdrawal of all funds if you have received this card from an untrusted source.</string>
<string name="alert_title">Warning</string>
<string name="alert_unsupported_card">This card it is not designed to work with Tangem</string>
<string name="alert_unsupported_card">This card is not designed to work with this app</string>
<string name="alert_developer_card">The card you scanned is a development card. Dont accept it as a payment</string>
<string name="alert_old_card">Tangem cards manufactured before September 2019 cannot currently be extracted with an iPhone. Were working hard with Apple to make it possible in future versions of iOS.</string>