Updated on 2026-08-14
This commit is contained in:
parent
10bb769916
commit
bb32839f9d
32 changed files with 521 additions and 77 deletions
|
|
@ -27,6 +27,7 @@ import com.tangem.domain.models.scan.ScanResponse
|
|||
import com.tangem.domain.visa.model.VisaActivationInput
|
||||
import com.tangem.domain.visa.model.VisaAuthChallenge
|
||||
import com.tangem.domain.visa.model.VisaCardActivationResponse
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
import com.tangem.operations.ScanTask
|
||||
|
|
@ -35,6 +36,7 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
|
|||
import com.tangem.operations.derivation.DeriveWalletPublicKeyTask
|
||||
import com.tangem.operations.pins.SetUserCodeCommand
|
||||
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||
import com.tangem.operations.sign.SignHashResponse
|
||||
import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
|
|
@ -45,6 +47,7 @@ import com.tangem.tap.domain.tasks.product.ResetBackupCardTask
|
|||
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
|
||||
import com.tangem.tap.domain.tasks.product.ScanProductTask
|
||||
import com.tangem.tap.domain.tasks.visa.VisaCardActivationTask
|
||||
import com.tangem.tap.domain.tasks.visa.VisaCustomerWalletApproveTask
|
||||
import com.tangem.tap.domain.twins.CreateFirstTwinWalletTask
|
||||
import com.tangem.tap.domain.twins.CreateSecondTwinWalletTask
|
||||
import com.tangem.tap.domain.twins.FinalizeTwinTask
|
||||
|
|
@ -494,6 +497,17 @@ internal class DefaultTangemSdkManager(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun visaCustomerWalletApprove(
|
||||
visaDataForApprove: VisaDataForApprove,
|
||||
): CompletionResult<SignHashResponse> {
|
||||
return runTaskAsyncReturnOnMain(
|
||||
runnable = VisaCustomerWalletApproveTask(
|
||||
visaDataForApprove = visaDataForApprove,
|
||||
),
|
||||
initialMessage = Message(resources.getStringSafe(R.string.initial_message_tap_header)),
|
||||
)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ import com.tangem.domain.models.scan.ScanResponse
|
|||
import com.tangem.domain.visa.model.VisaActivationInput
|
||||
import com.tangem.domain.visa.model.VisaAuthChallenge
|
||||
import com.tangem.domain.visa.model.VisaCardActivationResponse
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||
import com.tangem.operations.sign.SignHashResponse
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
|
|
@ -207,4 +209,12 @@ class MockTangemSdkManager(
|
|||
): CompletionResult<VisaCardActivationResponse> {
|
||||
error("Not implemented")
|
||||
}
|
||||
|
||||
override suspend fun visaCustomerWalletApprove(
|
||||
visaDataForApprove: VisaDataForApprove,
|
||||
): CompletionResult<SignHashResponse> {
|
||||
error("Not implemented")
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -311,15 +311,12 @@ private class ScanWalletProcessor(
|
|||
}
|
||||
|
||||
private fun getWalletProductType(card: CardDTO): ProductType {
|
||||
if (RING_BATCH_IDS.contains(card.batchId) || card.batchId.startsWith(RING_BATCH_PREFIX)) {
|
||||
return ProductType.Ring
|
||||
}
|
||||
return if (card.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available &&
|
||||
card.settings.isKeysImportAllowed
|
||||
) {
|
||||
ProductType.Wallet2
|
||||
} else {
|
||||
ProductType.Wallet
|
||||
return when {
|
||||
card.isVisa -> ProductType.Visa
|
||||
RING_BATCH_IDS.contains(card.batchId) || card.batchId.startsWith(RING_BATCH_PREFIX) -> ProductType.Ring
|
||||
card.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available &&
|
||||
card.settings.isKeysImportAllowed -> ProductType.Wallet2
|
||||
else -> ProductType.Wallet
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.tap.domain.tasks.visa
|
||||
|
||||
import com.reown.util.hexToBytes
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.map
|
||||
import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
||||
|
|
|
|||
|
|
@ -0,0 +1,188 @@
|
|||
package com.tangem.tap.domain.tasks.visa
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.card.CardWallet
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.visa.VisaUtilities
|
||||
import com.tangem.domain.common.visa.VisaWalletPublicKeyUtility
|
||||
import com.tangem.domain.common.visa.VisaWalletPublicKeyUtility.findKeyWithoutDerivation
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.visa.model.VisaActivationError
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.operations.ScanTask
|
||||
import com.tangem.operations.derivation.DeriveWalletPublicKeyTask
|
||||
import com.tangem.operations.sign.SignHashCommand
|
||||
import com.tangem.operations.sign.SignHashResponse
|
||||
|
||||
class VisaCustomerWalletApproveTask(
|
||||
private val visaDataForApprove: VisaDataForApprove,
|
||||
) : CardSessionRunnable<SignHashResponse> {
|
||||
|
||||
override fun run(session: CardSession, callback: CompletionCallback<SignHashResponse>) {
|
||||
val card = session.environment.card ?: run {
|
||||
callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
|
||||
return
|
||||
}
|
||||
|
||||
if (VisaUtilities.isVisaCard(card.firmwareVersion.doubleValue, card.batchId).not()) {
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying("Card is identified as not Visa")))
|
||||
return
|
||||
}
|
||||
|
||||
if (card.settings.isHDWalletAllowed) {
|
||||
proceedApprove(card, session, callback)
|
||||
} else {
|
||||
proceedApproveWithLegacyCard(card, session, callback)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedApprove(card: Card, session: CardSession, callback: CompletionCallback<SignHashResponse>) {
|
||||
val cardDTO = CardDTO(card)
|
||||
|
||||
val derivationStyle = cardDTO.derivationStyleProvider.getDerivationStyle() ?: run {
|
||||
proceedApproveWithLegacyCard(
|
||||
card = card,
|
||||
session = session,
|
||||
callback = callback,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val derivationPath = VisaUtilities.visaDefaultDerivationPath(derivationStyle) ?: run {
|
||||
callback(
|
||||
CompletionResult.Failure(
|
||||
TangemSdkError.Underlying("Failed to generate derivation path with provided derivation style"),
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val wallet = card.wallets.firstOrNull { it.curve == VisaUtilities.mandatoryCurve } ?: run {
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying(VisaActivationError.MissingWallet.message)))
|
||||
return
|
||||
}
|
||||
|
||||
val derivationTask = DeriveWalletPublicKeyTask(
|
||||
walletPublicKey = wallet.publicKey,
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
|
||||
derivationTask.run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
processDerivedKey(
|
||||
wallet = wallet,
|
||||
extendedPublicKey = result.data,
|
||||
derivationPath = derivationPath,
|
||||
session = session,
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processDerivedKey(
|
||||
wallet: CardWallet,
|
||||
extendedPublicKey: ExtendedPublicKey,
|
||||
derivationPath: DerivationPath,
|
||||
session: CardSession,
|
||||
callback: CompletionCallback<SignHashResponse>,
|
||||
) {
|
||||
val validationResult = VisaWalletPublicKeyUtility.validateExtendedPublicKey(
|
||||
targetAddress = visaDataForApprove.targetAddress,
|
||||
extendedPublicKey = extendedPublicKey,
|
||||
)
|
||||
|
||||
validationResult.onLeft {
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying(it.message)))
|
||||
return
|
||||
}
|
||||
|
||||
signApproveData(
|
||||
targetWalletPublicKey = wallet.publicKey,
|
||||
derivationPath = derivationPath,
|
||||
session = session,
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
|
||||
private fun proceedApproveWithLegacyCard(
|
||||
card: Card,
|
||||
session: CardSession,
|
||||
callback: CompletionCallback<SignHashResponse>,
|
||||
) {
|
||||
val publicKey = findKeyWithoutDerivation(
|
||||
targetAddress = visaDataForApprove.targetAddress,
|
||||
card = CardDTO(card),
|
||||
).getOrElse {
|
||||
callback(CompletionResult.Failure(TangemSdkError.Underlying(it.message)))
|
||||
return
|
||||
}
|
||||
|
||||
signApproveData(
|
||||
targetWalletPublicKey = publicKey,
|
||||
derivationPath = null,
|
||||
session = session,
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
|
||||
private fun signApproveData(
|
||||
targetWalletPublicKey: ByteArray,
|
||||
derivationPath: DerivationPath?,
|
||||
session: CardSession,
|
||||
callback: CompletionCallback<SignHashResponse>,
|
||||
) {
|
||||
val signTask = SignHashCommand(
|
||||
hash = visaDataForApprove.approveHash.hexToBytes(),
|
||||
walletPublicKey = targetWalletPublicKey,
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
|
||||
signTask.run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
scanCard(
|
||||
signHashResponse = result.data,
|
||||
session = session,
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun scanCard(
|
||||
signHashResponse: SignHashResponse,
|
||||
session: CardSession,
|
||||
callback: CompletionCallback<SignHashResponse>,
|
||||
) {
|
||||
val scanTask = ScanTask()
|
||||
scanTask.run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
callback(CompletionResult.Success(signHashResponse))
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
callback(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor(
|
|||
|
||||
override suspend fun getActivationRemoteState(): VisaActivationRemoteState = withContext(dispatcherProvider.io) {
|
||||
visaActivationStatusConverter.convert(visaApi.getRemoteActivationStatus(cardId))
|
||||
VisaActivationRemoteState.CardWalletSignatureRequired // mock
|
||||
// TODO implement refreshing access token if it's expired
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.domain.common
|
||||
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.domain.common.TapWorkarounds.isWallet2
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
|
||||
interface DerivationStyleProvider {
|
||||
|
|
@ -8,14 +9,13 @@ interface DerivationStyleProvider {
|
|||
}
|
||||
|
||||
internal class TangemDerivationStyleProvider(
|
||||
private val cardTypesResolver: CardTypesResolver,
|
||||
private val card: CardDTO,
|
||||
) : DerivationStyleProvider {
|
||||
override fun getDerivationStyle(): DerivationStyle? {
|
||||
return when {
|
||||
!card.settings.isHDWalletAllowed -> null
|
||||
firstBatchesOfWallet1(card) -> DerivationStyle.V1
|
||||
cardTypesResolver.isWallet2() -> DerivationStyle.V3
|
||||
card.isWallet2 -> DerivationStyle.V3
|
||||
else -> DerivationStyle.V2
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.common.card.WalletData
|
|||
import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.TapWorkarounds.isWallet2
|
||||
import com.tangem.domain.common.visa.VisaUtilities
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
|
|
@ -35,10 +36,7 @@ internal class TangemCardTypesResolver(
|
|||
return walletData == null && card.firmwareVersion <= FirmwareVersion.HDWalletAvailable
|
||||
}
|
||||
|
||||
override fun isWallet2(): Boolean {
|
||||
return card.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available &&
|
||||
card.settings.isKeysImportAllowed
|
||||
}
|
||||
override fun isWallet2(): Boolean = card.isWallet2
|
||||
|
||||
override fun isVisaWallet(): Boolean = productType == ProductType.Visa
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ object TapWorkarounds {
|
|||
val CardDTO.isStart2Coin: Boolean
|
||||
get() = isStart2CoinIssuer(issuer.name)
|
||||
|
||||
val CardDTO.isWallet2: Boolean
|
||||
get() = firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available && settings.isKeysImportAllowed
|
||||
|
||||
val CardDTO.isVisa: Boolean
|
||||
get() = VisaUtilities.isVisaCard(this)
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ val ScanResponse.cardTypesResolver: CardTypesResolver
|
|||
)
|
||||
|
||||
val ScanResponse.derivationStyleProvider: DerivationStyleProvider
|
||||
get() = TangemDerivationStyleProvider(
|
||||
cardTypesResolver,
|
||||
card,
|
||||
)
|
||||
get() = card.derivationStyleProvider
|
||||
|
||||
val CardDTO.derivationStyleProvider: DerivationStyleProvider
|
||||
get() = TangemDerivationStyleProvider(this)
|
||||
|
||||
val UserWallet.cardTypesResolver: CardTypesResolver
|
||||
get() = scanResponse.cardTypesResolver
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ object VisaUtilities {
|
|||
|
||||
val visaDefaultDerivationPath = visaBlockchain.derivationPath(DerivationStyle.V3)
|
||||
|
||||
fun visaDefaultDerivationPath(style: DerivationStyle) = visaBlockchain.derivationPath(style)
|
||||
|
||||
fun isVisaCard(card: CardDTO): Boolean {
|
||||
return isVisaCard(card.firmwareVersion.doubleValue, card.batchId)
|
||||
}
|
||||
|
||||
fun isVisaCard(firmwareVersion: Double, batchId: String): Boolean {
|
||||
return FirmwareVersion.visaRange.contains(firmwareVersion) &&
|
||||
return firmwareVersion in FirmwareVersion.visaRange &&
|
||||
batchId.startsWith(VISA_BATCH_START)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package com.tangem.domain.common.visa
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
|
||||
object VisaWalletPublicKeyUtility {
|
||||
|
||||
fun validateExtendedPublicKey(targetAddress: String, extendedPublicKey: ExtendedPublicKey): Either<Error, Unit> =
|
||||
either {
|
||||
validatePublicKey(
|
||||
targetAddress = targetAddress,
|
||||
publicKey = extendedPublicKey.publicKey,
|
||||
).bind()
|
||||
}
|
||||
|
||||
fun findKeyWithoutDerivation(targetAddress: String, card: CardDTO): Either<Error, ByteArray> = either {
|
||||
val wallet = findWalletOnVisaCurve(card).bind()
|
||||
|
||||
validatePublicKey(
|
||||
targetAddress = targetAddress,
|
||||
publicKey = wallet.publicKey,
|
||||
).bind()
|
||||
|
||||
wallet.publicKey
|
||||
}
|
||||
|
||||
private fun findWalletOnVisaCurve(card: CardDTO): Either<Error, CardDTO.Wallet> = either {
|
||||
card.wallets.firstOrNull { it.curve == VisaUtilities.mandatoryCurve } ?: raise(Error.MissingWalletOnTargetCurve)
|
||||
}
|
||||
|
||||
private fun validatePublicKey(targetAddress: String, publicKey: ByteArray): Either<Error, Unit> = either {
|
||||
val address = generateAddressOnVisaCurve(publicKey).bind()
|
||||
|
||||
if (address.value != targetAddress) {
|
||||
raise(Error.AddressNotMatched)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateAddressOnVisaCurve(walletPublicKey: ByteArray): Either<Error, Address> = either {
|
||||
val addresses = catch(
|
||||
block = {
|
||||
VisaUtilities.visaBlockchain.makeAddresses(
|
||||
walletPublicKey = walletPublicKey,
|
||||
pairPublicKey = null,
|
||||
curve = VisaUtilities.mandatoryCurve,
|
||||
)
|
||||
},
|
||||
catch = { raise(Error.FailedToCreateAddress) },
|
||||
)
|
||||
|
||||
addresses.firstOrNull() ?: raise(Error.FailedToCreateAddress)
|
||||
}
|
||||
|
||||
enum class Error(val message: String) {
|
||||
AddressNotMatched("ValidationError: Address not matched"),
|
||||
FailedToCreateAddress("ValidationError: Failed to create address"),
|
||||
MissingWalletOnTargetCurve("ValidationError: Missing wallet on target curve"),
|
||||
}
|
||||
}
|
||||
|
|
@ -4,5 +4,6 @@ enum class VisaActivationError(val message: String) {
|
|||
BlockedForActivation("Card is blocked for activation"),
|
||||
InvalidActivationState("Invalid activation state"),
|
||||
WrongCard("Wrong card tapped"),
|
||||
MissingWallet("Missing wallet"),
|
||||
MissingRootOTP("Missing root OTP"),
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.domain.visa.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class VisaDataForApprove(
|
||||
@SerialName("targetAddress") val targetAddress: String,
|
||||
@SerialName("approveHash") val approveHash: String,
|
||||
)
|
||||
|
|
@ -41,6 +41,7 @@ dependencies {
|
|||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.onboarding)
|
||||
implementation(projects.domain.visa)
|
||||
|
||||
/** Tangem libraries */
|
||||
implementation(projects.libs.tangemSdkApi)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,11 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
MutableSharedFlow<Unit>()
|
||||
}
|
||||
|
||||
private val childParams = ChildParams(
|
||||
onBack = ::onChildBack,
|
||||
parentBackEvent = currentChildBackEventHandle,
|
||||
)
|
||||
|
||||
private val stackNavigation = StackNavigation<OnboardingVisaRoute>()
|
||||
|
||||
private val childStack: Value<ChildStack<OnboardingVisaRoute, ComposableContentComponent>> =
|
||||
|
|
@ -76,7 +81,7 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
if (childStack.value.active.configuration is OnboardingVisaRoute.AccessCode) {
|
||||
componentScope.launch { currentChildBackEventHandle.emit(Unit) }
|
||||
} else {
|
||||
stackNavigation.pop()
|
||||
onChildBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -90,11 +95,7 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val childParams = ChildParams(
|
||||
onBack = ::onChildBack,
|
||||
parentBackEvent = currentChildBackEventHandle,
|
||||
)
|
||||
|
||||
@Suppress("LongMethod")
|
||||
private fun createChild(
|
||||
route: OnboardingVisaRoute,
|
||||
factoryContext: AppComponentContext,
|
||||
|
|
@ -112,10 +113,24 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
appComponentContext = factoryContext,
|
||||
params = OnboardingVisaAccessCodeComponent.Params(
|
||||
childParams = childParams,
|
||||
onDone = { stackNavigation.push(OnboardingVisaRoute.ChooseWallet) },
|
||||
onDone = {
|
||||
stackNavigation.push(
|
||||
if (it.walletFound) {
|
||||
OnboardingVisaRoute.TangemWalletApproveOption(
|
||||
visaDataForApprove = it.visaDataForApprove,
|
||||
allowNavigateBack = false,
|
||||
)
|
||||
} else {
|
||||
OnboardingVisaRoute.ChooseWallet(it.visaDataForApprove)
|
||||
},
|
||||
)
|
||||
},
|
||||
),
|
||||
config = OnboardingVisaAccessCodeComponent.Config(
|
||||
scanResponse = params.scanResponse,
|
||||
),
|
||||
)
|
||||
OnboardingVisaRoute.ChooseWallet -> OnboardingVisaChooseWalletComponent(
|
||||
is OnboardingVisaRoute.ChooseWallet -> OnboardingVisaChooseWalletComponent(
|
||||
appComponentContext = factoryContext,
|
||||
params = OnboardingVisaChooseWalletComponent.Params(
|
||||
childParams = childParams,
|
||||
|
|
@ -123,9 +138,12 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
stackNavigation.push(
|
||||
when (event) {
|
||||
OnboardingVisaChooseWalletComponent.Params.Event.TangemWallet ->
|
||||
OnboardingVisaRoute.TangemWalletApproveOption
|
||||
OnboardingVisaRoute.TangemWalletApproveOption(
|
||||
visaDataForApprove = route.visaDataForApprove,
|
||||
allowNavigateBack = true,
|
||||
)
|
||||
OnboardingVisaChooseWalletComponent.Params.Event.OtherWallet ->
|
||||
OnboardingVisaRoute.OtherWalletApproveOption
|
||||
OnboardingVisaRoute.OtherWalletApproveOption(route.visaDataForApprove)
|
||||
},
|
||||
)
|
||||
},
|
||||
|
|
@ -138,8 +156,11 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
onDone = { stackNavigation.push(OnboardingVisaRoute.PinCode) },
|
||||
),
|
||||
)
|
||||
OnboardingVisaRoute.OtherWalletApproveOption -> OnboardingVisaOtherWalletComponent(
|
||||
is OnboardingVisaRoute.OtherWalletApproveOption -> OnboardingVisaOtherWalletComponent(
|
||||
appComponentContext = factoryContext,
|
||||
config = OnboardingVisaOtherWalletComponent.Config(
|
||||
visaDataForApprove = route.visaDataForApprove,
|
||||
),
|
||||
params = OnboardingVisaOtherWalletComponent.Params(
|
||||
childParams = childParams,
|
||||
onDone = { stackNavigation.push(OnboardingVisaRoute.InProgress) },
|
||||
|
|
@ -152,8 +173,11 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
onDone = { params.onDone() },
|
||||
),
|
||||
)
|
||||
OnboardingVisaRoute.TangemWalletApproveOption -> OnboardingVisaApproveComponent(
|
||||
is OnboardingVisaRoute.TangemWalletApproveOption -> OnboardingVisaApproveComponent(
|
||||
appComponentContext = factoryContext,
|
||||
config = OnboardingVisaApproveComponent.Config(
|
||||
visaDataForApprove = route.visaDataForApprove,
|
||||
),
|
||||
params = OnboardingVisaApproveComponent.Params(
|
||||
childParams = childParams,
|
||||
onDone = { stackNavigation.push(OnboardingVisaRoute.InProgress) },
|
||||
|
|
@ -163,15 +187,24 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun onChildBack() {
|
||||
when (childStack.value.active.configuration) {
|
||||
if (childStack.value.backStack.size == 1) {
|
||||
// TODO show dialog
|
||||
return
|
||||
}
|
||||
|
||||
when (val route = childStack.value.active.configuration) {
|
||||
OnboardingVisaRoute.AccessCode,
|
||||
OnboardingVisaRoute.TangemWalletApproveOption,
|
||||
OnboardingVisaRoute.OtherWalletApproveOption,
|
||||
is OnboardingVisaRoute.OtherWalletApproveOption,
|
||||
-> stackNavigation.pop()
|
||||
is OnboardingVisaRoute.TangemWalletApproveOption -> {
|
||||
if (route.allowNavigateBack) {
|
||||
stackNavigation.pop()
|
||||
}
|
||||
}
|
||||
|
||||
is OnboardingVisaRoute.Welcome,
|
||||
OnboardingVisaRoute.ChooseWallet,
|
||||
is OnboardingVisaRoute.ChooseWallet,
|
||||
OnboardingVisaRoute.InProgress,
|
||||
OnboardingVisaRoute.OtherWalletApproveOption,
|
||||
OnboardingVisaRoute.PinCode,
|
||||
-> {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.features.onboarding.v2.visa.impl.DefaultOnboardingVisaComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.model.OnboardingVisaAccessCodeModel
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.OnboardingVisaAccessCode
|
||||
|
|
@ -16,10 +18,11 @@ import kotlinx.coroutines.launch
|
|||
|
||||
internal class OnboardingVisaAccessCodeComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
config: Config,
|
||||
private val params: Params,
|
||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: OnboardingVisaAccessCodeModel = getOrCreateModel()
|
||||
private val model: OnboardingVisaAccessCodeModel = getOrCreateModel(config)
|
||||
|
||||
init {
|
||||
componentScope.launch {
|
||||
|
|
@ -31,7 +34,7 @@ internal class OnboardingVisaAccessCodeComponent(
|
|||
}
|
||||
}
|
||||
componentScope.launch {
|
||||
model.onDone.collect { params.onDone() }
|
||||
model.onDone.collect { params.onDone(it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,8 +49,17 @@ internal class OnboardingVisaAccessCodeComponent(
|
|||
OnboardingVisaAccessCode(state, modifier)
|
||||
}
|
||||
|
||||
data class Config(
|
||||
val scanResponse: ScanResponse,
|
||||
)
|
||||
|
||||
data class Params(
|
||||
val childParams: DefaultOnboardingVisaComponent.ChildParams,
|
||||
val onDone: () -> Unit,
|
||||
val onDone: (DoneEvent) -> Unit,
|
||||
)
|
||||
|
||||
data class DoneEvent(
|
||||
val visaDataForApprove: VisaDataForApprove,
|
||||
val walletFound: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
@ -2,8 +2,15 @@ package com.tangem.features.onboarding.v2.visa.impl.child.accesscode.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.OnboardingVisaAccessCodeComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.state.OnboardingVisaAccessCodeUM
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -14,15 +21,22 @@ import javax.inject.Inject
|
|||
@Stable
|
||||
@ComponentScoped
|
||||
internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val visaAuthRepository: VisaAuthRepository,
|
||||
) : Model() {
|
||||
|
||||
private val params: OnboardingVisaAccessCodeComponent.Config = paramsContainer.require()
|
||||
private val activationStatus =
|
||||
params.scanResponse.visaCardActivationStatus as? VisaCardActivationStatus.NotStartedActivation
|
||||
?: error("Visa activation status is not set or incorrect for this step")
|
||||
|
||||
private val _uiState = MutableStateFlow(getInitialState())
|
||||
val uiState = _uiState.asStateFlow()
|
||||
val onBack = MutableSharedFlow<Unit>()
|
||||
val onDone = MutableSharedFlow<Unit>()
|
||||
val onDone = MutableSharedFlow<OnboardingVisaAccessCodeComponent.DoneEvent>()
|
||||
|
||||
fun onBack() {
|
||||
when (uiState.value.step) {
|
||||
|
|
@ -97,27 +111,53 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun startActivationProcess(accessCode: String) {
|
||||
modelScope.launch { onDone.emit(Unit) }
|
||||
loading(true)
|
||||
|
||||
// modelScope.launch {
|
||||
// @Suppress("UnusedPrivateMember")
|
||||
// val result = tangemSdkManager.activateVisaCard(
|
||||
// accessCode = accessCode,
|
||||
// challengeToSign = null,
|
||||
// activationInput = TODO(),
|
||||
// )
|
||||
//
|
||||
// when (result) {
|
||||
// is CompletionResult.Success -> {
|
||||
// val response = result.data
|
||||
// TODO()
|
||||
// }
|
||||
// is CompletionResult.Failure -> {
|
||||
// // show alert
|
||||
// TODO()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
modelScope.launch {
|
||||
val challengeToSign = runCatching {
|
||||
visaAuthRepository.getCardAuthChallenge(
|
||||
cardId = activationStatus.activationInput.cardId,
|
||||
cardPublicKey = activationStatus.activationInput.cardPublicKey.toHexString(),
|
||||
)
|
||||
}.getOrElse {
|
||||
loading(false)
|
||||
// show alert
|
||||
return@launch
|
||||
}
|
||||
|
||||
val result = tangemSdkManager.activateVisaCard(
|
||||
accessCode = accessCode,
|
||||
challengeToSign = challengeToSign,
|
||||
activationInput = activationStatus.activationInput,
|
||||
)
|
||||
//
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
// TODO load approve data from backend
|
||||
// TODO try to find wallet in the app
|
||||
|
||||
modelScope.launch {
|
||||
onDone.emit(
|
||||
OnboardingVisaAccessCodeComponent.DoneEvent(
|
||||
visaDataForApprove = VisaDataForApprove(
|
||||
targetAddress = "x9F65354e595284956599F2892fA4A4a87653D6E6",
|
||||
approveHash = "approve hash",
|
||||
),
|
||||
walletFound = false, // TODO
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
// show alert
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loading(state: Boolean) {
|
||||
_uiState.update { it.copy(buttonLoading = state) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ internal fun OnboardingVisaAccessCode(state: OnboardingVisaAccessCodeUM, modifie
|
|||
},
|
||||
onClick = state.onContinue,
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
showProgress = state.buttonLoading,
|
||||
isIconVisible = state.step == OnboardingVisaAccessCodeUM.Step.ReEnter,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ internal data class OnboardingVisaAccessCodeUM(
|
|||
val codesNotMatchError: Boolean = false,
|
||||
val atLeastMinCharsError: Boolean = false,
|
||||
val accessCodeHidden: Boolean = true,
|
||||
val buttonLoading: Boolean = false,
|
||||
val onAccessCodeFirstChange: (TextFieldValue) -> Unit = {},
|
||||
val onAccessCodeSecondChange: (TextFieldValue) -> Unit = {},
|
||||
val onContinue: () -> Unit = {},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.features.onboarding.v2.visa.impl.DefaultOnboardingVisaComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.approve.model.OnboardingVisaApproveModel
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.OnboardingVisaApprove
|
||||
|
|
@ -16,10 +17,11 @@ import kotlinx.coroutines.launch
|
|||
|
||||
internal class OnboardingVisaApproveComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
config: Config,
|
||||
private val params: Params,
|
||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: OnboardingVisaApproveModel = getOrCreateModel()
|
||||
private val model: OnboardingVisaApproveModel = getOrCreateModel(config)
|
||||
|
||||
init {
|
||||
componentScope.launch {
|
||||
|
|
@ -39,6 +41,10 @@ internal class OnboardingVisaApproveComponent(
|
|||
)
|
||||
}
|
||||
|
||||
data class Config(
|
||||
val visaDataForApprove: VisaDataForApprove,
|
||||
)
|
||||
|
||||
data class Params(
|
||||
val childParams: DefaultOnboardingVisaComponent.ChildParams,
|
||||
val onDone: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -1,22 +1,30 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.approve.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.approve.OnboardingVisaApproveComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.state.OnboardingVisaApproveUM
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ComponentScoped
|
||||
internal class OnboardingVisaApproveModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<OnboardingVisaApproveComponent.Config>()
|
||||
private val _uiState = MutableStateFlow(getInitialState())
|
||||
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
|
@ -29,7 +37,29 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onApproveClick() {
|
||||
// TODO
|
||||
modelScope.launch { onDone.emit(Unit) }
|
||||
loading(true)
|
||||
|
||||
modelScope.launch {
|
||||
val result = tangemSdkManager.visaCustomerWalletApprove(
|
||||
visaDataForApprove = params.visaDataForApprove,
|
||||
)
|
||||
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
// TODO make backend call
|
||||
|
||||
onDone.emit(Unit)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
// TODO show dialog
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loading(state: Boolean) {
|
||||
_uiState.update { it.copy(approveButtonLoading = state) }
|
||||
}
|
||||
}
|
||||
|
|
@ -68,6 +68,7 @@ internal fun OnboardingVisaApprove(state: OnboardingVisaApproveUM, modifier: Mod
|
|||
textReference = TextReference.Str("Approve"),
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
isIconVisible = true,
|
||||
showProgress = state.approveButtonLoading,
|
||||
onClick = state.onApproveClick,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.state
|
||||
|
||||
internal data class OnboardingVisaApproveUM(
|
||||
val approveButtonLoading: Boolean = false,
|
||||
val onApproveClick: () -> Unit = {},
|
||||
)
|
||||
|
|
@ -9,6 +9,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.features.onboarding.v2.visa.impl.DefaultOnboardingVisaComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.model.OnboardingVisaOtherWalletModel
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.OnboardingVisaOtherWallet
|
||||
|
|
@ -17,10 +18,11 @@ import kotlinx.coroutines.flow.onEach
|
|||
|
||||
internal class OnboardingVisaOtherWalletComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
config: Config,
|
||||
private val params: Params,
|
||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: OnboardingVisaOtherWalletModel = getOrCreateModel()
|
||||
private val model: OnboardingVisaOtherWalletModel = getOrCreateModel(config)
|
||||
|
||||
init {
|
||||
model.onDone
|
||||
|
|
@ -40,6 +42,10 @@ internal class OnboardingVisaOtherWalletComponent(
|
|||
)
|
||||
}
|
||||
|
||||
data class Config(
|
||||
val visaDataForApprove: VisaDataForApprove,
|
||||
)
|
||||
|
||||
data class Params(
|
||||
val childParams: DefaultOnboardingVisaComponent.ChildParams,
|
||||
val onDone: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.model
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.OnboardingVisaOtherWalletComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.state.OnboardingVisaOtherWalletUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -13,9 +15,12 @@ import javax.inject.Inject
|
|||
@Stable
|
||||
@ComponentScoped
|
||||
internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private val config = paramsContainer.require<OnboardingVisaOtherWalletComponent.Config>()
|
||||
private val _uiState = MutableStateFlow(getInitialState())
|
||||
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -95,16 +96,18 @@ fun Artwork(modifier: Modifier = Modifier) {
|
|||
Box(modifier) {
|
||||
val circleColor = TangemTheme.colors.background.secondary
|
||||
var cardHeightPx by remember { mutableIntStateOf(0) }
|
||||
val circleRadiusPx = cardHeightPx / 2 + cardHeightPx / 8f
|
||||
val circleSize = with(LocalDensity.current) { (circleRadiusPx * 2).toDp() }
|
||||
|
||||
Canvas(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(254.dp)
|
||||
.size(circleSize)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
drawCircle(
|
||||
color = circleColor,
|
||||
radius = cardHeightPx / 2 + cardHeightPx / 8f,
|
||||
radius = circleRadiusPx,
|
||||
center = center,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.route
|
||||
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
|
|
@ -12,13 +13,16 @@ sealed class OnboardingVisaRoute {
|
|||
data object AccessCode : OnboardingVisaRoute()
|
||||
|
||||
@Serializable
|
||||
data object ChooseWallet : OnboardingVisaRoute()
|
||||
data class ChooseWallet(val visaDataForApprove: VisaDataForApprove) : OnboardingVisaRoute()
|
||||
|
||||
@Serializable
|
||||
data object TangemWalletApproveOption : OnboardingVisaRoute()
|
||||
data class TangemWalletApproveOption(
|
||||
val visaDataForApprove: VisaDataForApprove,
|
||||
val allowNavigateBack: Boolean,
|
||||
) : OnboardingVisaRoute()
|
||||
|
||||
@Serializable
|
||||
data object OtherWalletApproveOption : OnboardingVisaRoute()
|
||||
data class OtherWalletApproveOption(val visaDataForApprove: VisaDataForApprove) : OnboardingVisaRoute()
|
||||
|
||||
@Serializable
|
||||
data object InProgress : OnboardingVisaRoute()
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ package com.tangem.features.onboarding.v2.visa.impl.route
|
|||
internal fun OnboardingVisaRoute.stepNum() = when (this) {
|
||||
is OnboardingVisaRoute.Welcome -> 1
|
||||
OnboardingVisaRoute.AccessCode -> 2
|
||||
OnboardingVisaRoute.ChooseWallet -> 3
|
||||
OnboardingVisaRoute.OtherWalletApproveOption -> 4
|
||||
OnboardingVisaRoute.TangemWalletApproveOption -> 4
|
||||
is OnboardingVisaRoute.ChooseWallet -> 3
|
||||
is OnboardingVisaRoute.OtherWalletApproveOption -> 4
|
||||
is OnboardingVisaRoute.TangemWalletApproveOption -> 4
|
||||
OnboardingVisaRoute.InProgress -> 5
|
||||
OnboardingVisaRoute.PinCode -> 6
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
// TODO add translations [REDACTED_TASK_KEY]
|
||||
internal fun OnboardingVisaRoute.screenTitle(): TextReference = when (this) {
|
||||
OnboardingVisaRoute.AccessCode -> TextReference.Str("Access code")
|
||||
OnboardingVisaRoute.ChooseWallet -> TextReference.Str("Account activation")
|
||||
is OnboardingVisaRoute.ChooseWallet -> TextReference.Str("Account activation")
|
||||
OnboardingVisaRoute.InProgress -> TextReference.Str("In progress")
|
||||
OnboardingVisaRoute.OtherWalletApproveOption -> TextReference.Str("Wallet connection")
|
||||
is OnboardingVisaRoute.OtherWalletApproveOption -> TextReference.Str("Wallet connection")
|
||||
OnboardingVisaRoute.PinCode -> TextReference.Str("PIN code")
|
||||
OnboardingVisaRoute.TangemWalletApproveOption -> TextReference.Str("Wallet connection")
|
||||
is OnboardingVisaRoute.TangemWalletApproveOption -> TextReference.Str("Wallet connection")
|
||||
is OnboardingVisaRoute.Welcome -> TextReference.Str("Getting started")
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
internal fun OnboardingVisa(modifier: Modifier = Modifier, childContent: @Composable (Modifier) -> Unit) {
|
||||
childContent(modifier)
|
||||
}
|
||||
|
|
@ -18,9 +18,11 @@ import com.tangem.domain.models.scan.ScanResponse
|
|||
import com.tangem.domain.visa.model.VisaActivationInput
|
||||
import com.tangem.domain.visa.model.VisaAuthChallenge
|
||||
import com.tangem.domain.visa.model.VisaCardActivationResponse
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||
import com.tangem.operations.sign.SignHashResponse
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
|
|
@ -153,5 +155,7 @@ interface TangemSdkManager {
|
|||
activationInput: VisaActivationInput,
|
||||
): CompletionResult<VisaCardActivationResponse>
|
||||
|
||||
suspend fun visaCustomerWalletApprove(visaDataForApprove: VisaDataForApprove): CompletionResult<SignHashResponse>
|
||||
|
||||
// endregion
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue