Updated on 2026-08-14

This commit is contained in:
Tangem 2022-01-26 20:25:32 +03:00
parent 102f4cf536
commit a370de2bcb
19 changed files with 110 additions and 648 deletions

View file

@ -77,9 +77,9 @@ 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:develop-53'
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-115'
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-115'
implementation 'com.tangem:blockchain:BSK-107_update_sdk-54'
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-125'
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-125'
// WebView
implementation "androidx.browser:browser:1.3.0"

@ -1 +1 @@
Subproject commit e80938f7d9ba378a91ac544a9170597e64afa696
Subproject commit 42803296690ad6914ec2c59c5fdc3f0fb30f8afc

View file

@ -105,6 +105,7 @@ object TangemSdk {
is TangemSdkError.WrongInteractionMode -> TangemSdkError.WrongInteractionMode()
is TangemSdkError.IssuerSignatureLoadingFailed -> TangemSdkError.IssuerSignatureLoadingFailed()
is TangemSdkError.BackupFailedFirmware -> TangemSdkError.BackupFailedFirmware()
is TangemSdkError.UserForgotTheCode -> TangemSdkError.UserForgotTheCode()
}
}

View file

@ -1,17 +0,0 @@
package com.tangem.tap.common.extensions
/**
[REDACTED_AUTHOR]
*/
data class ByteArrayKey(val bytes: ByteArray) {
override fun equals(other: Any?): Boolean {
return this === other || other is ByteArrayKey && this.bytes.contentEquals(other.bytes)
}
override fun hashCode(): Int = bytes.contentHashCode()
}
fun ByteArray.toMapKey(): ByteArrayKey = ByteArrayKey(this)
fun ByteArrayKey.bytes(): ByteArray = this.bytes

View file

@ -1,147 +0,0 @@
package com.tangem.tap.common.leapfrogWidget
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.view.animation.LinearInterpolator
/**
[REDACTED_AUTHOR]
*/
//fun View.setForeground(hasForegroundAtEnd: Boolean) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// foreground = getForegroundDrawable()
// }
//}
//fun View.getForegroundDrawable(): Drawable? {
// return AppCompatResources.getDrawable(context, R.drawable.shape_rectangle_rounded_8_op_20)?.also {
// it.alpha = 60
// }
//}
typealias ProgressListener = (Int) -> Unit
fun createProgressListener(duration: Long, listener: ProgressListener?): Animator {
val valueAnimator = ValueAnimator.ofInt(0, 100)
valueAnimator.duration = duration
valueAnimator.addUpdateListener { listener?.invoke((it.animatedValue as? Int) ?: 0) }
return valueAnimator
}
fun View.unfoldAnimation(animDuration: Long, properties: LeapViewProperties): AnimatorSet {
val translate = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, properties.yTranslation)
translate.duration = animDuration
return AnimatorSet().apply { playTogether(translate) }
}
fun View.foldAnimation(animDuration: Long, properties: LeapViewProperties): AnimatorSet {
val translate = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, properties.yTranslation)
translate.duration = animDuration
return AnimatorSet().apply {
playSequentially(translate)
}
}
fun View.leapAnimation(animDuration: Long, properties: LeapViewProperties, overLift: Float): AnimatorSet {
val halfDuration = animDuration / 2
val upTo = (height.toFloat() + overLift) * -1
val translateUp = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, upTo)
translateUp.duration = halfDuration
translateUp.interpolator = LinearInterpolator()
val scaleDuration = halfDuration - halfDuration / 5
val scaleX = ObjectAnimator.ofFloat(this, View.SCALE_X, properties.scale)
val scaleY = ObjectAnimator.ofFloat(this, View.SCALE_Y, properties.scale)
val scale = AnimatorSet().apply {
startDelay = scaleDuration
duration = scaleDuration
interpolator = LinearInterpolator()
playTogether(scaleX, scaleY)
}
val elevation = elevationAnimator(properties.elevationStart, properties.elevationEnd, halfDuration, 100)
val translateDown = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, properties.yTranslation)
translateDown.startDelay = halfDuration
translateDown.duration = halfDuration
translateDown.interpolator = LinearInterpolator()
return AnimatorSet().apply {
playTogether(translateUp, scale, elevation, translateDown)
}
}
fun View.leapBackAnimation(animDuration: Long, properties: LeapViewProperties, calculator: PropertyCalculator): AnimatorSet {
val halfDuration = animDuration / 2
val upTo = ((height).toFloat() - calculator.yTranslationFactor) * -1
val translateUp = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, upTo)
translateUp.duration = halfDuration
translateUp.interpolator = LinearInterpolator()
val scaleDuration = halfDuration - halfDuration / 5
val scaleX = ObjectAnimator.ofFloat(this, View.SCALE_X, properties.scale)
val scaleY = ObjectAnimator.ofFloat(this, View.SCALE_Y, properties.scale)
val scale = AnimatorSet().apply {
startDelay = scaleDuration
duration = scaleDuration
interpolator = LinearInterpolator()
playTogether(scaleX, scaleY)
}
val elevation = elevationAnimator(properties.elevationStart, properties.elevationEnd, halfDuration, 100)
val translateDown = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, properties.yTranslation)
translateDown.startDelay = halfDuration
translateDown.duration = halfDuration
return AnimatorSet().apply {
playTogether(translateUp, scale, elevation, translateDown)
}
}
fun View.pullUpAnimation(leapDuration: Long, properties: LeapViewProperties): AnimatorSet {
val pullDuration = leapDuration / 2
val delayDuration = leapDuration / 2
val translateUp = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, properties.yTranslation)
val scaleX = ObjectAnimator.ofFloat(this, View.SCALE_X, properties.scale)
val scaleY = ObjectAnimator.ofFloat(this, View.SCALE_Y, properties.scale)
val elevation = elevationAnimator(properties.elevationStart, properties.elevationEnd)
return AnimatorSet().apply {
startDelay = delayDuration
duration = pullDuration
interpolator = DecelerateInterpolator()
playTogether(translateUp, scaleX, scaleY, elevation)
}
}
fun View.pullDownAnimation(leapDuration: Long, properties: LeapViewProperties): AnimatorSet {
val pullDuration = leapDuration / 2
val delayDuration = leapDuration / 4
val translate = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, properties.yTranslation)
val scaleX = ObjectAnimator.ofFloat(this, View.SCALE_X, properties.scale)
val scaleY = ObjectAnimator.ofFloat(this, View.SCALE_Y, properties.scale)
val elevation = elevationAnimator(properties.elevationStart, properties.elevationEnd)
return AnimatorSet().apply {
startDelay = delayDuration
duration = pullDuration
interpolator = DecelerateInterpolator()
playTogether(translate, scaleX, scaleY, elevation)
}
}
fun View.elevationAnimator(start: Float, end: Float, startDelay: Long? = null, duration: Long? = null): Animator {
val elevationAnimator = ValueAnimator.ofFloat(start, end)
elevationAnimator.addUpdateListener { this.elevation = (it.animatedValue as? Float) ?: start }
startDelay?.let { elevationAnimator.startDelay = it }
duration?.let { elevationAnimator.duration = it }
return elevationAnimator
}

View file

@ -1,144 +0,0 @@
package com.tangem.tap.common.leapfrogWidget
import android.view.View
/**
[REDACTED_AUTHOR]
*/
class LeapView(
val view: View,
val index: Int,
position: Int,
private val maximalPosition: Int,
private val calculator: PropertyCalculator,
) {
var state: LeapViewState
private set
val initialState: LeapViewState
init {
val initialProperties = createInitialProperty(position)
state = LeapViewState(index, position, position, initialProperties)
initialState = state.copy()
}
fun initView() {
applyState(initialState)
}
fun leap(): LeapFrogAnimation {
val previousPosition = state.currentPosition
val currentPosition = when (previousPosition) {
0 -> maximalPosition
else -> state.currentPosition - 1
}
state = state.copy(
currentPosition = currentPosition,
previousPosition = previousPosition,
properties = createLeapAnimationProperty(previousPosition, currentPosition)
)
return when {
previousPosition == 0 && currentPosition == maximalPosition -> LeapFrogAnimation.LEAP
else -> LeapFrogAnimation.PULL
}
}
fun leapBack(): LeapFrogAnimation {
val previousPosition = state.currentPosition
val currentPosition = when (previousPosition) {
maximalPosition -> 0
else -> state.currentPosition + 1
}
state = state.copy(
currentPosition = currentPosition,
previousPosition = previousPosition,
properties = createLeapAnimationProperty(previousPosition, currentPosition)
)
return when {
previousPosition == maximalPosition && currentPosition == 0 -> LeapFrogAnimation.LEAP
else -> LeapFrogAnimation.PULL
}
}
fun fold() {
state = state.copy(properties = state.properties.toFold()
)
}
fun unfold() {
state = state.copy(properties = state.properties.toUnfold(calculator))
}
fun applyState(state: LeapViewState) {
this.state = state
setProperties(this.state.properties)
}
private fun setProperties(properties: LeapViewProperties) {
view.elevation = properties.elevationEnd
view.translationY = properties.yTranslation
view.scaleX = properties.scale
view.scaleY = properties.scale
// initialProperties.hasForeground
}
private fun createInitialProperty(endPosition: Int): LeapViewProperties {
return LeapViewProperties(
endPosition,
endPosition,
calculator.scale(endPosition),
calculator.elevation(endPosition, maximalPosition + 1),
calculator.elevation(endPosition, maximalPosition + 1),
calculator.yTranslation(0),
calculator.hasForeground(endPosition),
)
}
private fun createLeapAnimationProperty(startPosition: Int, endPosition: Int): LeapViewProperties {
return LeapViewProperties(
startPosition,
endPosition,
calculator.scale(endPosition),
calculator.elevation(startPosition, maximalPosition + 1),
calculator.elevation(endPosition, maximalPosition + 1),
calculator.yTranslation(endPosition),
calculator.hasForeground(endPosition),
)
}
private fun LeapViewProperties.toUnfold(calculator: PropertyCalculator): LeapViewProperties {
return this.copy(yTranslation = calculator.yTranslation(this.positionEnd))
}
private fun LeapViewProperties.toFold(): LeapViewProperties {
return this.copy(yTranslation = 0f)
}
override fun toString(): String = "index: $index, position: ${state.currentPosition}, code: ${view.hashCode()}"
}
data class LeapViewState(
val index: Int,
val currentPosition: Int,
val previousPosition: Int,
val properties: LeapViewProperties
)
enum class LeapFrogAnimation {
LEAP, PULL
}
data class LeapViewProperties(
val positionStart: Int,
val positionEnd: Int,
val scale: Float,
val elevationStart: Float,
val elevationEnd: Float,
val yTranslation: Float,
val hasForeground: Boolean,
)

View file

@ -1,249 +0,0 @@
package com.tangem.tap.common.leapfrogWidget
import android.animation.Animator
import android.animation.AnimatorSet
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.FrameLayout
import androidx.core.animation.doOnEnd
import androidx.core.view.children
import com.tangem.common.extensions.VoidCallback
import com.tangem.tangem_sdk_new.extensions.dpToPx
/**
[REDACTED_AUTHOR]
*/
class LeapfrogWidget(
private val parentContainer: FrameLayout,
private val calculator: PropertyCalculator = PropertyCalculator(),
) {
private val foldAnimationDuration = 300L
private val leapAnimationDuration = 500L
private val leapBackAnimationDuration = 500L
private val leapViews = mutableListOf<LeapView>()
private var foldUnfoldProgress: Int = 100
private var leapProgress: Int = 100
private var leapBackProgress: Int = 100
init {
calculator.setTranslationConverter { parentContainer.dpToPx(it) }
if (viewIsFullFledged()) {
val maxPosition = parentContainer.childCount - 1
parentContainer.children.forEachIndexed { index, view ->
val initialPosition = maxPosition - index
leapViews.add(LeapView(view, index, initialPosition, maxPosition, calculator))
}
}
}
/**
* Apply initial properties to the views
*/
fun initViews() {
leapViews.forEach { it.initView() }
}
fun fold(animate: Boolean = true, onEnd: VoidCallback = {}) {
val animator = foldAnimator(animate)
if (animator == null) {
onEnd()
} else {
animator.doOnEnd { onEnd() }
animator.start()
}
}
fun unfold(animate: Boolean = true, onEnd: VoidCallback = {}) {
val animator = unfoldAnimator(animate)
if (animator == null) {
onEnd()
} else {
animator.doOnEnd { onEnd() }
animator.start()
}
}
fun foldAnimator(animate: Boolean = true): Animator? {
if (!canFoldUnfold()) return null
return createFoldUnfoldAnimator(true, animate, foldAnimationDuration)
}
fun unfoldAnimator(animate: Boolean = true): Animator? {
if (!canFoldUnfold()) return null
return createFoldUnfoldAnimator(false, animate, foldAnimationDuration)
}
private fun createFoldUnfoldAnimator(isFoldAnimation: Boolean, animate: Boolean, duration: Long): Animator {
val animatorsList = mutableListOf<Animator>()
val animateDuration = if (animate) duration else 0
leapViews.forEach {
if (isFoldAnimation) {
it.fold()
animatorsList.add(it.view.foldAnimation(animateDuration, it.state.properties))
} else {
it.unfold()
animatorsList.add(it.view.unfoldAnimation(animateDuration, it.state.properties))
}
}
animatorsList.add(createProgressListener(animateDuration) { foldUnfoldProgress = it })
val animator = AnimatorSet()
animator.interpolator = AccelerateDecelerateInterpolator()
animator.playTogether(animatorsList.toList())
return animator
}
fun leap(animate: Boolean = true, onEnd: VoidCallback = {}) {
if (!canLeap()) {
onEnd()
return
}
val duration = if (animate) leapAnimationDuration else 0
val animatorsList = mutableListOf<Animator>()
leapViews.forEach {
when (it.leap()) {
LeapFrogAnimation.LEAP -> {
val overLift = calculator.overLift(leapViews.size)
animatorsList.add(it.view.leapAnimation(duration, it.state.properties, overLift))
}
LeapFrogAnimation.PULL -> {
animatorsList.add(it.view.pullUpAnimation(duration, it.state.properties))
}
}
}
animatorsList.add(createProgressListener(duration) { leapProgress = it })
val animator = AnimatorSet()
animator.playTogether(animatorsList.toList())
animator.doOnEnd { onEnd() }
animator.start()
}
fun leapBack(animate: Boolean = true, onEnd: VoidCallback = {}) {
if (!canLeapBack()) {
onEnd()
return
}
val duration = if (animate) leapBackAnimationDuration else 0
val animatorsList = mutableListOf<Animator>()
leapViews.forEach {
when (it.leapBack()) {
LeapFrogAnimation.LEAP -> {
animatorsList.add(it.view.leapBackAnimation(duration, it.state.properties, calculator))
}
LeapFrogAnimation.PULL -> {
animatorsList.add(it.view.pullDownAnimation(duration, it.state.properties))
}
}
}
animatorsList.add(createProgressListener(duration) { leapBackProgress = it })
val animator = AnimatorSet()
animator.playTogether(animatorsList.toList())
animator.doOnEnd { onEnd() }
animator.start()
}
fun getViewsCount(): Int = parentContainer.childCount
fun getViewPositionByIndex(index: Int): Int = leapViews.first { it.index == index }.state.currentPosition
fun getViewByPosition(position: Int): LeapView = leapViews.first { it.state.currentPosition == position }
fun getState(): LeapfrogWidgetState = LeapfrogWidgetState(leapViews.map { it.state })
fun applyState(state: LeapfrogWidgetState) {
state.leapViewStates.forEach { viewState ->
leapViews.firstOrNull { it.index == viewState.index }?.applyState(viewState)
}
}
private fun viewIsFullFledged(): Boolean = parentContainer.childCount > 1
private fun canFoldUnfold(): Boolean {
return when {
!viewIsFullFledged() -> false
foldUnfoldInProgress() -> false
leapInProgress() || leapBackInProgress() -> false
else -> true
}
}
private fun canLeap(): Boolean {
return when {
!viewIsFullFledged() -> false
leapBackInProgress() -> false
leapProgress < 70 -> false
else -> true
}
}
private fun canLeapBack(): Boolean {
return when {
!viewIsFullFledged() -> false
leapInProgress() -> false
leapBackProgress < 70 -> false
else -> true
}
}
private fun foldUnfoldInProgress(): Boolean = foldUnfoldProgress != 100
private fun leapInProgress(): Boolean = leapProgress != 100
private fun leapBackInProgress(): Boolean = leapBackProgress != 100
}
data class LeapfrogWidgetState(
val leapViewStates: List<LeapViewState>
)
class PropertyCalculator(
val elevationFactor: Float = 1f,
val decreaseScaleFactor: Float = 0.15f,
val yTranslationFactor: Float = 35f,
val decreaseOverLiftingFactor: Float = 0.85f,
) {
// 0 view it is view on the top of stack, but it is last in parent.children
private var translationValueConverter: ((Float) -> Float)? = null
fun setTranslationConverter(converter: (Float) -> Float) {
translationValueConverter = converter
}
fun scale(position: Int): Float {
return 1f - decreaseScaleFactor * position
}
fun elevation(position: Int, count: Int): Float {
return elevationFactor * (count - 1 - position)
}
fun yTranslation(position: Int): Float {
val yTranslation = yTranslationFactor * position
return convertTranslation(yTranslation)
}
fun hasForeground(position: Int): Boolean {
return position != 0
}
fun overLift(viewCount: Int): Float {
val initialOverLift = when {
yTranslationFactor < 0f -> yTranslationFactor * decreaseOverLiftingFactor * viewCount * -1
else -> 10f
}
val scaleOverLift = when {
decreaseScaleFactor == 0f -> initialOverLift
else -> initialOverLift * decreaseOverLiftingFactor - initialOverLift * decreaseScaleFactor
}
return convertTranslation(scaleOverLift)
}
private fun convertTranslation(value: Float): Float {
return translationValueConverter?.invoke(value) ?: value
}
}

View file

@ -5,6 +5,8 @@ import android.view.View
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidgetState
import com.tangem.tap.domain.twins.TwinsCardWidget
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.test_leapfrog_fragment.*

View file

@ -14,18 +14,18 @@ import com.tangem.common.core.CardIdDisplayFormat
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.Config
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.operations.CommandResponse
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.pins.CheckUserCodesCommand
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.operations.pins.SetUserCodeCommand
import com.tangem.tap.common.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.AnalyticsHandler
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
import com.tangem.tap.common.extensions.ByteArrayKey
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
import com.tangem.tap.domain.tasks.DerivationTask
import com.tangem.tap.domain.tasks.DerivationTaskResponse
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
import com.tangem.tap.domain.tasks.product.ScanResponse
@ -81,7 +81,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
cardId: String,
derivations: Map<ByteArrayKey, List<DerivationPath>>
): CompletionResult<DerivationTaskResponse> {
return runTaskAsyncReturnOnMain(DerivationTask(derivations), cardId)
return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId)
}
suspend fun resetToFactorySettings(card: Card): CompletionResult<Card> {

View file

@ -6,7 +6,7 @@ import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.common.card.CardWallet
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.hexToBytes
import com.tangem.tap.common.extensions.toMapKey
import com.tangem.common.extensions.toMapKey
import com.tangem.tap.domain.TapWorkarounds.isTestCard
import com.tangem.tap.domain.tasks.product.ScanResponse
@ -33,13 +33,23 @@ fun WalletManagerFactory.makeWalletManagerForApp(
}
seedKey != null -> {
val derivedKeys = scanResponse.derivedKeys[wallet.publicKey.toMapKey()]
val derivedKey = derivedKeys?.firstOrNull { it.derivationPath == blockchain.derivationPath() }
val derivedKey = derivedKeys?.get(blockchain.derivationPath())
?: return null
makeWalletManager(card.cardId, environmentBlockchain, seedKey, derivedKey)
makeWalletManager(
cardId = card.cardId,
blockchain = environmentBlockchain,
seedKey = wallet.publicKey,
derivedKey = derivedKey
)
}
else -> {
makeWalletManager(card.cardId, environmentBlockchain, wallet.publicKey, wallet.curve)
makeWalletManager(
cardId = card.cardId,
blockchain = environmentBlockchain,
walletPublicKey = wallet.publicKey,
curve = wallet.curve
)
}
}
}

View file

@ -1,50 +1,55 @@
package com.tangem.tap.domain.tasks
import com.tangem.common.CompletionResult
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.CompletionCallback
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.operations.CommandResponse
import com.tangem.operations.derivation.DeriveWalletPublicKeysTask
import com.tangem.operations.derivation.ExtendedPublicKeyList
import com.tangem.tap.common.extensions.ByteArrayKey
class DerivationTaskResponse(
val entries: Map<ByteArrayKey, ExtendedPublicKeyList>
): CommandResponse
class DerivationTask(
private val derivations: Map<ByteArrayKey, List<DerivationPath>>
) : CardSessionRunnable<DerivationTaskResponse> {
val response: MutableMap<ByteArrayKey, ExtendedPublicKeyList> = mutableMapOf()
override fun run(session: CardSession, callback: CompletionCallback<DerivationTaskResponse>) {
derive(keys = derivations.keys.toList(), index = 0, session = session, callback = callback)
}
private fun derive(
keys: List<ByteArrayKey>,
index: Int,
session: CardSession,
callback: CompletionCallback<DerivationTaskResponse>
) {
if (index == keys.count()) {
callback(CompletionResult.Success(DerivationTaskResponse(response.toMap())))
return
}
val key = keys[index]
val paths = derivations[key]!!
DeriveWalletPublicKeysTask(key.bytes, paths).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
response[key] = result.data
derive(keys = keys, index = index + 1, session = session, callback = callback)
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
}
//package com.tangem.tap.domain.tasks
//
//import com.tangem.common.CompletionResult
//import com.tangem.common.core.CardSession
//import com.tangem.common.core.CardSessionRunnable
//import com.tangem.common.core.CompletionCallback
//import com.tangem.common.hdWallet.DerivationPath
//import com.tangem.common.hdWallet.ExtendedPublicKey
//import com.tangem.operations.CommandResponse
//import com.tangem.operations.derivation.DeriveWalletPublicKeysTask
//import com.tangem.tap.common.extensions.ByteArrayKey
//
//class ExtendedPublicKeyList(
// items: Collection<ExtendedPublicKey>
//): ArrayList<ExtendedPublicKey>(items), CommandResponse
//
//
//class DerivationTaskResponse(
// val entries: Map<ByteArrayKey, ExtendedPublicKeyList>
//): CommandResponse
//
//class DerivationTask(
// private val derivations: Map<ByteArrayKey, List<DerivationPath>>
//) : CardSessionRunnable<DerivationTaskResponse> {
//
// val response: MutableMap<ByteArrayKey, ExtendedPublicKeyList> = mutableMapOf()
//
// override fun run(session: CardSession, callback: CompletionCallback<DerivationTaskResponse>) {
// derive(keys = derivations.keys.toList(), index = 0, session = session, callback = callback)
// }
//
// private fun derive(
// keys: List<ByteArrayKey>,
// index: Int,
// session: CardSession,
// callback: CompletionCallback<DerivationTaskResponse>
// ) {
// if (index == keys.count()) {
// callback(CompletionResult.Success(DerivationTaskResponse(response.toMap())))
// return
// }
//
// val key = keys[index]
// val paths = derivations[key]!!
// DeriveWalletPublicKeysTask(key.bytes, paths).run(session) { result ->
// when (result) {
// is CompletionResult.Success -> {
// response[key] = result.data[key]
// derive(keys = keys, index = index + 1, session = session, callback = callback)
// }
// is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
// }
// }
// }
//}

View file

@ -6,16 +6,16 @@ import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.hdWallet.ExtendedPublicKey
import com.tangem.common.extensions.toMapKey
import com.tangem.operations.CommandResponse
import com.tangem.operations.backup.PrimaryCard
import com.tangem.operations.backup.StartPrimaryCardLinkingTask
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask
import com.tangem.tap.common.extensions.toMapKey
import com.tangem.tap.domain.ProductType
import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.tap.domain.tasks.DerivationTask
import com.tangem.tap.domain.tasks.product.CreateWalletsTask
import com.tangem.tap.domain.tasks.product.KeyWalletPublicKey
import com.tangem.tap.domain.tasks.product.ProductCommandProcessor
@ -24,7 +24,7 @@ import com.tangem.tap.domain.tasks.product.getCurvesForNonCreatedWallets
data class CreateProductWalletTaskResponse(
val card: Card,
val derivedKeys: Map<KeyWalletPublicKey, List<ExtendedPublicKey>> = mapOf(),
val derivedKeys: Map<KeyWalletPublicKey, ExtendedPublicKeysMap> = mapOf(),
val primaryCard: PrimaryCard? = null
) : CommandResponse
@ -170,7 +170,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
return
}
DerivationTask(mapOf(response.wallet.publicKey.toMapKey() to derivationPaths))
DeriveMultipleWalletPublicKeysTask(mapOf(response.wallet.publicKey.toMapKey() to derivationPaths))
.run(session) { result ->
when (result) {
is CompletionResult.Success -> {

View file

@ -12,19 +12,20 @@ import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toHexString
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.common.hdWallet.ExtendedPublicKey
import com.tangem.operations.CommandResponse
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.ScanTask
import com.tangem.operations.backup.PrimaryCard
import com.tangem.operations.backup.StartPrimaryCardLinkingTask
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.tap.common.extensions.ByteArrayKey
import com.tangem.tap.common.extensions.toMapKey
import com.tangem.tap.domain.ProductType
import com.tangem.tap.domain.TapSdkError
import com.tangem.tap.domain.TapWorkarounds
@ -33,7 +34,6 @@ import com.tangem.tap.domain.TapWorkarounds.isExcluded
import com.tangem.tap.domain.TapWorkarounds.isNotSupportedInThatRelease
import com.tangem.tap.domain.extensions.getPrimaryCurve
import com.tangem.tap.domain.extensions.getSingleWallet
import com.tangem.tap.domain.tasks.DerivationTask
import com.tangem.tap.domain.tokens.CurrenciesRepository
import com.tangem.tap.domain.twins.TwinsHelper
import com.tangem.tap.preferencesStorage
@ -43,7 +43,7 @@ data class ScanResponse(
val productType: ProductType,
val walletData: WalletData?,
val secondTwinPublicKey: String? = null,
val derivedKeys: Map<KeyWalletPublicKey, List<ExtendedPublicKey>> = mapOf(),
val derivedKeys: Map<KeyWalletPublicKey, ExtendedPublicKeysMap> = mapOf(),
val primaryCard: PrimaryCard? = null
) : CommandResponse {
@ -253,7 +253,7 @@ private class ScanWalletProcessor(
return
}
DerivationTask(derivations).run(session) { result ->
DeriveMultipleWalletPublicKeysTask(derivations).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
val response = ScanResponse(

View file

@ -6,9 +6,10 @@ import android.animation.PropertyValuesHolder
import android.view.View
import androidx.core.animation.doOnEnd
import com.tangem.common.extensions.VoidCallback
import com.tangem.tap.common.leapfrogWidget.LeapView
import com.tangem.tap.common.leapfrogWidget.LeapViewState
import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapView
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapViewState
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
/**
[REDACTED_AUTHOR]

View file

@ -8,7 +8,7 @@ import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.guard
import com.tangem.common.files.FileHashHelper
import com.tangem.operations.files.FileHashHelper
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.operations.issuerAndUserData.ReadIssuerDataResponse
import com.tangem.operations.issuerAndUserData.WriteIssuerDataCommand

View file

@ -12,8 +12,8 @@ import com.squareup.picasso.Picasso
import com.tangem.Message
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.VoidCallback
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.common.redux.navigation.ShareElement

View file

@ -6,9 +6,9 @@ import android.animation.PropertyValuesHolder
import android.view.View
import android.widget.ImageView
import androidx.core.animation.doOnEnd
import com.tangem.tap.common.leapfrogWidget.LeapView
import com.tangem.tap.common.leapfrogWidget.LeapViewState
import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapView
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapViewState
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
class BackupCardsWidget(
val leapfrogWidget: LeapfrogWidget,

View file

@ -12,10 +12,10 @@ import com.google.android.material.tabs.TabLayoutMediator
import com.squareup.picasso.Picasso
import com.tangem.common.CardIdFormatter
import com.tangem.common.core.CardIdDisplayFormat
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.leapfrogWidget.LeapfrogWidget
import com.tangem.tap.common.postUi
import com.tangem.tap.features.FragmentOnBackPressedHandler
import com.tangem.tap.features.addBackPressHandler

View file

@ -4,11 +4,11 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.common.CompletionResult
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.common.hdWallet.ExtendedPublicKey
import com.tangem.tap.common.extensions.ByteArrayKey
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.toMapKey
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.NavigationAction
@ -94,14 +94,14 @@ class TokensMiddleware {
is CompletionResult.Success -> {
val newDerivedKeys = result.data.entries
val updatedDerivedKeys =
mutableMapOf<KeyWalletPublicKey, List<ExtendedPublicKey>>()
mutableMapOf<KeyWalletPublicKey, ExtendedPublicKeysMap>()
newDerivedKeys.forEach { entry ->
val derivationData = derivationDataList.find {
it.mapKeyOfWalletPublicKey == entry.key
} ?: return@forEach
updatedDerivedKeys[entry.key] =
derivationData.alreadyDerivedKeys + entry.value.toList()
ExtendedPublicKeysMap(derivationData.alreadyDerivedKeys + entry.value)
}
val updatedScanResponse = scanResponse.copy(
@ -133,9 +133,9 @@ class TokensMiddleware {
.mapNotNull { it.derivationPath() }
val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
val alreadyDerivedKeys =
scanResponse.derivedKeys[mapKeyOfWalletPublicKey]?.toMutableList() ?: mutableListOf()
val alreadyDerivedPaths = alreadyDerivedKeys.map { it.derivationPath }
val alreadyDerivedKeys: ExtendedPublicKeysMap =
scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList()
val toDerive = derivationPathsCandidates.filterNot { alreadyDerivedPaths.contains(it) }
return DerivationData(
@ -147,7 +147,7 @@ class TokensMiddleware {
private class DerivationData(
val derivations: Pair<ByteArrayKey, List<DerivationPath>>,
val alreadyDerivedKeys: List<ExtendedPublicKey>,
val alreadyDerivedKeys: ExtendedPublicKeysMap,
val mapKeyOfWalletPublicKey: ByteArrayKey
)