Updated on 2026-08-14

This commit is contained in:
Tangem 2021-10-22 12:17:20 +00:00
commit 7e5716a13d
13 changed files with 65 additions and 38 deletions

@ -1 +1 @@
Subproject commit 0cf3af21e6f441e6323a1ba127ee7518168797df
Subproject commit e80938f7d9ba378a91ac544a9170597e64afa696

View file

@ -99,11 +99,10 @@ class TapWalletManager {
store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard))
store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed))
if (data.card.isTwinCard()) {
val secondCardId = TwinsHelper.getTwinsCardId(data.card.cardId)
val cardNumber = TwinsHelper.getTwinCardNumber(data.card.cardId)
if (secondCardId != null && cardNumber != null) {
if (cardNumber != null) {
store.dispatch(WalletAction.TwinsAction.SetTwinCard(
secondCardId, cardNumber, isCreatingTwinCardsAllowed = true
cardNumber, isCreatingTwinCardsAllowed = true
))
}
}

View file

@ -20,6 +20,7 @@ import com.tangem.tap.domain.TapSdkError
import com.tangem.tap.domain.TapWorkarounds.isExcluded
import com.tangem.tap.domain.TapWorkarounds.isMultiCurrencyWallet
import com.tangem.tap.domain.TapWorkarounds.noteCurrency
import com.tangem.tap.domain.TapWorkarounds.isNote
import com.tangem.tap.domain.extensions.getSingleWallet
import com.tangem.tap.domain.twins.TwinCardsManager
import com.tangem.tap.domain.twins.isTwinCard
@ -31,7 +32,6 @@ data class ScanNoteResponse(
val walletData: WalletData?,
val secondTwinPublicKey: String? = null,
) : CommandResponse {
fun getBlockchain(): Blockchain? {
if (card.noteCurrency != null) return card.noteCurrency
val blockchainName: String = walletData?.blockchain ?: return null
@ -148,14 +148,14 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
private fun getErrorIfExcludedCard(card: Card): TangemError? {
if (card.isExcluded()) return TapSdkError.CardForDifferentApp
// Disable new multi-currency HD wallet cards on the old version of the app
if (card.isMultiCurrencyWallet()) return UpdateAppToUseThisCard()
// Disable new cards on the old version of the app // TODO: remove when cards are supported
if (card.isMultiCurrencyWallet() || card.isNote()) return UpdateAppToUseThisCard()
return null
}
private fun getWalletManagerFactory(): WalletManagerFactory {
val blockchainSdkConfig = store.state.globalState.configManager?.config
?.blockchainSdkConfig ?: BlockchainSdkConfig()
?.blockchainSdkConfig ?: BlockchainSdkConfig()
return WalletManagerFactory(blockchainSdkConfig)
}

View file

@ -6,6 +6,7 @@ import com.tangem.common.KeyPair
import com.tangem.common.card.EllipticCurve
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.hexToBytes
import com.tangem.operations.wallet.CreateWalletCommand
import com.tangem.operations.wallet.CreateWalletResponse
@ -13,14 +14,21 @@ import com.tangem.operations.wallet.PurgeWalletCommand
import com.tangem.tap.domain.extensions.getSingleWallet
class CreateSecondTwinWalletTask(
private val firstPublicKey: String,
private val issuerKeys: KeyPair,
private val preparingMessage: Message,
private val creatingWalletMessage: Message
private val firstPublicKey: String,
private val firstCardId: String,
private val issuerKeys: KeyPair,
private val preparingMessage: Message,
private val creatingWalletMessage: Message
) : CardSessionRunnable<CreateWalletResponse> {
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
val publicKey = session.environment.card?.getSingleWallet()?.publicKey
val card = session.environment.card
val publicKey = card?.getSingleWallet()?.publicKey
if (publicKey != null) {
if (!card.cardId.startsWith(TwinsHelper.getPairCardSeries(firstCardId) ?: "")) {
callback(CompletionResult.Failure(TangemSdkError.WrongCardType()))
return
}
session.setInitialMessage(preparingMessage)
PurgeWalletCommand(publicKey).run(session) { response ->
when (response) {

View file

@ -21,7 +21,6 @@ import com.tangem.tap.tangemSdkManager
class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context: Context) {
private val currentCardId: String = scanNoteResponse.card.cardId
private val secondCardId: String? = TwinsHelper.getTwinsCardId(currentCardId)
private var currentCardPublicKey: String? = null
private var secondCardPublicKey: String? = null
@ -59,13 +58,15 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context:
preparingMessage: Message,
creatingWalletMessage: Message,
): SimpleResult {
val task = CreateSecondTwinWalletTask(
firstPublicKey = currentCardPublicKey!!,
firstCardId = currentCardId,
issuerKeys = issuerKeyPair,
preparingMessage = preparingMessage,
creatingWalletMessage = creatingWalletMessage
)
val response = tangemSdkManager.runTaskAsync(
CreateSecondTwinWalletTask(
firstPublicKey = currentCardPublicKey!!,
issuerKeys = issuerKeyPair,
preparingMessage = preparingMessage,
creatingWalletMessage = creatingWalletMessage),
secondCardId, initialMessage
task, null, initialMessage
)
when (response) {
is CompletionResult.Success -> {

View file

@ -22,6 +22,19 @@ class TwinsHelper {
}
}
fun getPairCardSeries(cardId: String): String? {
return when (getTwinCardNumber(cardId) ?: return null) {
TwinCardNumber.First -> {
val index = firstCardSeries.indexOf(cardId.take(4))
secondCardSeries[index]
}
TwinCardNumber.Second -> {
val index = secondCardSeries.indexOf(cardId.take(4))
firstCardSeries[index]
}
}
}
fun getTwinsCardId(cardId: String): String? {
val cardIdWithNewSeries = when (getTwinCardNumber(cardId) ?: return null) {
TwinCardNumber.First -> {

View file

@ -172,12 +172,16 @@ private fun handleSecurityAction(
state.copy(confirmScreenState = confirmScreenState)
}
is DetailsAction.ManageSecurity.SaveChanges.Success -> {
// Setting options to show only LongTap from now on
// Setting options to show only LongTap from now on for non-twins
state.copy(
securityScreenState = state.securityScreenState?.copy(
currentOption = state.securityScreenState.selectedOption,
allowedOptions = EnumSet.of(SecurityOption.LongTap)
))
securityScreenState = state.securityScreenState?.copy(
currentOption = state.securityScreenState.selectedOption,
allowedOptions = state.card?.let {
prepareAllowedSecurityOptions(
it, state.securityScreenState.selectedOption
)
} ?: EnumSet.of(SecurityOption.LongTap)
))
}
else -> state
@ -188,8 +192,11 @@ private fun prepareAllowedSecurityOptions(
card: Card?, currentSecurityOption: SecurityOption?
): EnumSet<SecurityOption> {
val prohibitDefaultPin = card?.settings?.isRemovingAccessCodeAllowed != true
val allowedSecurityOptions = EnumSet.noneOf(SecurityOption::class.java)
if (card?.isTwinCard() == true) {
allowedSecurityOptions.add(SecurityOption.PassCode)
}
if ((currentSecurityOption == SecurityOption.LongTap) || !prohibitDefaultPin) {
allowedSecurityOptions.add(SecurityOption.LongTap)
}

View file

@ -152,8 +152,8 @@ sealed class WalletAction : Action {
object ShowOnboarding : TwinsAction()
object SetOnboardingShown : TwinsAction()
data class SetTwinCard(
val secondCardId: String, val number: TwinCardNumber,
val isCreatingTwinCardsAllowed: Boolean,
val number: TwinCardNumber,
val isCreatingTwinCardsAllowed: Boolean,
) : TwinsAction()
}
}

View file

@ -195,7 +195,6 @@ data class TradeCryptoAvailability(
)
data class TwinCardsState(
val secondCardId: String?,
val cardNumber: TwinCardNumber?,
val showTwinOnboarding: Boolean,
val isCreatingTwinCardsAllowed: Boolean

View file

@ -109,7 +109,7 @@ class WalletMiddleware {
when (result) {
is CompletionResult.Success -> {
val scanNoteResponse =
globalState?.scanNoteResponse?.copy(card = result.data)
globalState?.scanNoteResponse?.copy(card = result.data)
scanNoteResponse?.let {
globalState.tapWalletManager.onCardScanned(scanNoteResponse)
}

View file

@ -10,7 +10,6 @@ class TwinsReducer {
is WalletAction.TwinsAction.SetTwinCard -> {
state.copy(
twinCardsState = TwinCardsState(
secondCardId = action.secondCardId,
cardNumber = action.number,
showTwinOnboarding = state.twinCardsState?.showTwinOnboarding
?: false,
@ -21,7 +20,7 @@ class TwinsReducer {
is WalletAction.TwinsAction.ShowOnboarding -> {
state.copy(
twinCardsState = state.twinCardsState?.copy(showTwinOnboarding = true)
?: TwinCardsState(null, null,
?: TwinCardsState(cardNumber = null,
showTwinOnboarding = true,
isCreatingTwinCardsAllowed = false)
)

View file

@ -94,7 +94,10 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
override fun newState(state: WalletState) {
if (activity == null) return
if (state.isMultiwalletAllowed && walletView is SingleWalletView) {
if (state.isMultiwalletAllowed &&
state.primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
walletView is SingleWalletView
) {
walletView = MultiWalletView()
walletView.changeWalletView(this)
} else if (!state.isMultiwalletAllowed && walletView is MultiWalletView) {

View file

@ -8,7 +8,6 @@ import androidx.transition.TransitionInflater
import com.squareup.picasso.Picasso
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.twins.TwinsHelper
import com.tangem.tap.features.wallet.redux.Artwork
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
@ -34,10 +33,9 @@ class TwinsOnboardingFragment : Fragment(R.layout.fragment_twin_cards) {
super.onViewCreated(view, savedInstanceState)
store.dispatch(WalletAction.TwinsAction.SetOnboardingShown)
val secondCardId = store.state.walletState.twinCardsState?.secondCardId ?: ""
val secondTwinCardId = TwinsHelper.getTwinCardIdForUser(secondCardId)
val text = getString(R.string.twins_onboarding_description_format, secondTwinCardId)
val secondTwinNumber =
store.state.walletState.twinCardsState?.cardNumber?.pairNumber()?.number ?: ""
val text = getString(R.string.twins_onboarding_description_format, secondTwinNumber)
tv_twin_cards_description_1.text = text
setOnClickListeners()