Updated on 2026-08-14

This commit is contained in:
Tangem 2021-10-13 18:54:49 +03:00
parent 0330285106
commit fd214bffd8
36 changed files with 313 additions and 261 deletions

View file

@ -74,7 +74,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
notificationsHandler = NotificationsHandler(fragment_container)
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
val isScannedBefore = store.state.globalState.scanNoteResponse != null
val isScannedBefore = store.state.globalState.scanResponse != null
val isOnboardingServiceActive = store.state.globalState.onboardingService != null
if (backStackIsEmpty || (!isOnboardingServiceActive && !isScannedBefore)) {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))

View file

@ -7,6 +7,7 @@ import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
import com.tangem.tap.features.disclaimer.redux.DisclaimerReducer
import com.tangem.tap.features.home.redux.HomeReducer
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteReducer
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsReducer
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletReducer
import com.tangem.tap.features.send.redux.reducers.SendScreenReducer
import com.tangem.tap.features.tokens.redux.TokensReducer
@ -23,6 +24,7 @@ fun appReducer(action: Action, state: AppState?): AppState {
homeState = HomeReducer.reduce(action, state),
onboardingNoteState = OnboardingNoteReducer.reduce(action, state),
onboardingWalletState = OnboardingWalletReducer.reduce(action, state),
onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state),
walletState = WalletReducer.reduce(action, state),
sendState = SendScreenReducer.reduce(action, state.sendState),
detailsState = DetailsReducer.reduce(action, state),

View file

@ -14,6 +14,8 @@ import com.tangem.tap.features.home.redux.HomeMiddleware
import com.tangem.tap.features.home.redux.HomeState
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteMiddleware
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteState
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsMiddleware
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsState
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletMiddleware
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
import com.tangem.tap.features.send.redux.middlewares.SendMiddleware
@ -31,6 +33,7 @@ data class AppState(
val homeState: HomeState = HomeState(),
val onboardingNoteState: OnboardingNoteState = OnboardingNoteState(),
val onboardingWalletState: OnboardingWalletState = OnboardingWalletState(),
val onboardingOtherCardsState: OnboardingOtherCardsState = OnboardingOtherCardsState(),
val walletState: WalletState = WalletState(),
val sendState: SendState = SendState(),
val detailsState: DetailsState = DetailsState(),
@ -47,6 +50,7 @@ data class AppState(
HomeMiddleware.handler,
OnboardingNoteMiddleware.handler,
OnboardingWalletMiddleware.handler,
OnboardingOtherCardsMiddleware.handler,
WalletMiddleware().walletMiddleware,
SendMiddleware().sendMiddleware,
DetailsMiddleware().detailsMiddleware,

View file

@ -8,7 +8,7 @@ import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.tap.features.feedback.EmailData
import com.tangem.tap.features.feedback.FeedbackManager
@ -34,18 +34,18 @@ sealed class GlobalAction : Action {
}
data class ReadCard(
val onSuccess: ((ScanNoteResponse) -> Unit)? = null,
val onSuccess: ((ScanResponse) -> Unit)? = null,
val onFailure: ((TangemError) -> Unit)? = null,
val messageResId: Int? = null,
) : GlobalAction()
object ScanFailsCounter {
data class ChooseBehavior(val result: CompletionResult<ScanNoteResponse>) : GlobalAction()
data class ChooseBehavior(val result: CompletionResult<ScanResponse>) : GlobalAction()
object Reset : GlobalAction()
object Increment : GlobalAction()
}
data class SaveScanNoteResponse(val scanNoteResponse: ScanNoteResponse) : GlobalAction()
data class SaveScanNoteResponse(val scanResponse: ScanResponse) : GlobalAction()
data class SetIfCardVerifiedOnline(val verified: Boolean) : GlobalAction()

View file

@ -23,7 +23,7 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
globalState.copy(scanCardFailsCounter = 0)
}
is GlobalAction.SaveScanNoteResponse ->
globalState.copy(scanNoteResponse = action.scanNoteResponse)
globalState.copy(scanResponse = action.scanResponse)
is GlobalAction.ChangeAppCurrency -> {
globalState.copy(appCurrency = action.appCurrency)
}
@ -35,17 +35,17 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
}
is GlobalAction.SetWarningManager -> globalState.copy(warningManager = action.warningManager)
is GlobalAction.UpdateWalletSignedHashes -> {
val wallet = globalState.scanNoteResponse?.card
val wallet = globalState.scanResponse?.card
?.wallet(action.walletPublicKey)
?.copy(
totalSignedHashes = action.walletSignedHashes,
remainingSignatures = action.remainingSignatures
)
val card = globalState.scanNoteResponse?.card
wallet?.let { globalState.scanNoteResponse.card.updateWallet(wallet) }
val card = globalState.scanResponse?.card
wallet?.let { globalState.scanResponse.card.updateWallet(wallet) }
if (card != null) {
globalState.copy(scanNoteResponse = globalState.scanNoteResponse.copy(card = card))
globalState.copy(scanResponse = globalState.scanResponse.copy(card = card))
} else {
globalState
}

View file

@ -6,7 +6,7 @@ import com.tangem.tap.domain.PayIdManager
import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.features.feedback.FeedbackManager
import com.tangem.tap.features.onboarding.service.ProductOnboardingService
import com.tangem.tap.network.coinmarketcap.CoinMarketCapService
@ -14,19 +14,19 @@ import com.tangem.tap.network.moonpay.MoonPayUserStatus
import org.rekotlin.StateType
data class GlobalState(
val scanNoteResponse: ScanNoteResponse? = null,
val cardVerifiedOnline: Boolean = false,
val tapWalletManager: TapWalletManager = TapWalletManager(),
val payIdManager: PayIdManager = PayIdManager(),
val coinMarketCapService: CoinMarketCapService = CoinMarketCapService(),
val configManager: ConfigManager? = null,
val warningManager: WarningMessagesManager? = null,
val feedbackManager: FeedbackManager? = null,
val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY,
val scanCardFailsCounter: Int = 0,
val dialog: StateDialog? = null,
val moonPayUserStatus: MoonPayUserStatus? = null,
val onboardingService: ProductOnboardingService? = null,
val scanResponse: ScanResponse? = null,
val cardVerifiedOnline: Boolean = false,
val tapWalletManager: TapWalletManager = TapWalletManager(),
val payIdManager: PayIdManager = PayIdManager(),
val coinMarketCapService: CoinMarketCapService = CoinMarketCapService(),
val configManager: ConfigManager? = null,
val warningManager: WarningMessagesManager? = null,
val feedbackManager: FeedbackManager? = null,
val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY,
val scanCardFailsCounter: Int = 0,
val dialog: StateDialog? = null,
val moonPayUserStatus: MoonPayUserStatus? = null,
val onboardingService: ProductOnboardingService? = null,
) : StateType
typealias CryptoCurrencyName = String

View file

@ -0,0 +1,8 @@
package com.tangem.tap.domain
/**
[REDACTED_AUTHOR]
*/
enum class ProductType {
Note, Wallet, Twin, Other
}

View file

@ -21,9 +21,8 @@ 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.domain.tasks.CreateWalletAndRescanTask
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.ScanNoteTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.domain.twins.isTangemTwin
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
@ -33,23 +32,10 @@ import kotlin.coroutines.suspendCoroutine
class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) {
@Deprecated("Use can product")
suspend fun scanNote(
analyticsHandler: AnalyticsHandler,
messageRes: Int? = null,
): CompletionResult<ScanNoteResponse> {
analyticsHandler.triggerEvent(AnalyticsEvent.READY_TO_SCAN, null)
return runTaskAsyncReturnOnMain(
ScanNoteTask(),
initialMessage = Message(context.getString(messageRes ?: R.string.initial_message_scan_header))
).also { sendScanFailuresToAnalytics(analyticsHandler, it) }
}
suspend fun scanProduct(
analyticsHandler: AnalyticsHandler,
messageRes: Int? = null,
): CompletionResult<ScanNoteResponse> {
): CompletionResult<ScanResponse> {
analyticsHandler.triggerEvent(AnalyticsEvent.READY_TO_SCAN, null)
val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header))
@ -57,13 +43,17 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
.also { sendScanFailuresToAnalytics(analyticsHandler, it) }
}
suspend fun createProductWallet(cardId: String?): CompletionResult<Card> {
return runTaskAsync(CreateProductWalletAndRescanTask(), cardId, Message(context.getString(R.string.initial_message_create_wallet_body)))
suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult<Card> {
return runTaskAsync(
CreateProductWalletAndRescanTask(scanResponse.productType),
scanResponse.card.cardId,
Message(context.getString(R.string.initial_message_create_wallet_body))
)
}
private fun sendScanFailuresToAnalytics(
analyticsHandler: AnalyticsHandler,
result: CompletionResult<ScanNoteResponse>
result: CompletionResult<ScanResponse>
) {
if (result is CompletionResult.Failure && result.error is TangemSdkError) {
(result.error as? TangemSdkError)?.let { error ->

View file

@ -14,7 +14,7 @@ import com.tangem.tap.domain.TapWorkarounds.isStart2Coin
import com.tangem.tap.domain.TapWorkarounds.isTestCard
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.tap.domain.extensions.*
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.domain.tokens.CardCurrencies
import com.tangem.tap.domain.twins.TwinsHelper
import com.tangem.tap.domain.twins.isTangemTwin
@ -77,7 +77,7 @@ class TapWalletManager {
handleFiatRatesResult(results)
}
suspend fun onCardScanned(data: ScanNoteResponse, addAnalyticsEvent: Boolean = false) {
suspend fun onCardScanned(data: ScanResponse, addAnalyticsEvent: Boolean = false) {
if (addAnalyticsEvent) {
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.CARD_IS_SCANNED, data.card, data.walletData?.blockchain)
}
@ -108,7 +108,7 @@ class TapWalletManager {
}
}
private fun updateConfigManager(data: ScanNoteResponse) {
private fun updateConfigManager(data: ScanResponse) {
val configManager = store.state.globalState.configManager
val blockchain = data.getBlockchain()
if (data.card.isStart2Coin) {
@ -124,7 +124,7 @@ class TapWalletManager {
}
}
suspend fun loadData(data: ScanNoteResponse) {
suspend fun loadData(data: ScanResponse) {
withContext(Dispatchers.Main) {
store.dispatch(WalletAction.LoadCardInfo(data.card))
@ -220,7 +220,7 @@ class TapWalletManager {
}
}
suspend fun reloadData(data: ScanNoteResponse) {
suspend fun reloadData(data: ScanResponse) {
withContext(Dispatchers.Main) {
when {
data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> {

View file

@ -8,7 +8,7 @@ import com.tangem.common.card.CardWallet
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.hexToBytes
import com.tangem.tap.domain.TapWorkarounds.isTestCard
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.domain.twins.isTangemTwin
fun WalletManagerFactory.makeWalletManagerForApp(
@ -50,7 +50,7 @@ fun WalletManagerFactory.makeWalletManagersForApp(
}
fun WalletManagerFactory.makePrimaryWalletManager(
data: ScanNoteResponse,
data: ScanResponse,
): WalletManager? {
val card = data.card
val blockchain = if (card.isTestCard) {

View file

@ -11,6 +11,7 @@ import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.wallet.CreateWalletCommand
@Deprecated("Use CreateProductWalletAndRescanTask instead")
class CreateWalletAndRescanTask : CardSessionRunnable<Card> {
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {

View file

@ -9,6 +9,7 @@ import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.wallet.CreateWalletCommand
@Deprecated("Use CreateProductWalletsResponse instead")
class CreateWalletsTask(curves: List<EllipticCurve>? = null) : CardSessionRunnable<Card> {
private val curves = curves ?: listOf(
@ -25,8 +26,8 @@ class CreateWalletsTask(curves: List<EllipticCurve>? = null) : CardSessionRunnab
}
private fun createWallet(
curve: EllipticCurve, session: CardSession,
callback: (result: CompletionResult<Card>) -> Unit
curve: EllipticCurve, session: CardSession,
callback: (result: CompletionResult<Card>) -> Unit
) {
CreateWalletCommand(curve).run(session) { result ->
@ -45,12 +46,4 @@ class CreateWalletsTask(curves: List<EllipticCurve>? = null) : CardSessionRunnab
}
}
}
}
private fun EllipticCurve.toWalletIndex(): Int {
return when (this) {
EllipticCurve.Secp256k1 -> 0
EllipticCurve.Ed25519 -> 1
EllipticCurve.Secp256r1 -> 2
}
}

View file

@ -1,56 +1,29 @@
package com.tangem.tap.domain.tasks
import com.tangem.*
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.card.WalletData
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemError
import com.tangem.common.extensions.toHexString
import com.tangem.operations.CommandResponse
import com.tangem.operations.ScanTask
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.tap.domain.ProductType
import com.tangem.tap.domain.TapSdkError
import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.tap.domain.TapWorkarounds.isExcluded
import com.tangem.tap.domain.TapWorkarounds.isTangemNote
import com.tangem.tap.domain.extensions.getSingleWallet
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.domain.twins.TwinCardsManager
import com.tangem.tap.domain.twins.isTangemTwin
data class ScanNoteResponse(
val card: Card,
val walletData: WalletData?,
val secondTwinPublicKey: String? = null,
) : CommandResponse {
fun getBlockchain(): Blockchain {
if (card.isTangemNote()) return card.getTangemNoteBlockchain() ?: return Blockchain.Unknown
val blockchainName: String = walletData?.blockchain ?: return Blockchain.Unknown
return Blockchain.fromId(blockchainName)
}
fun getPrimaryToken(): Token? {
val cardToken = walletData?.token ?: return null
return Token(
cardToken.name,
cardToken.symbol,
cardToken.contractAddress,
cardToken.decimals,
Blockchain.fromId(walletData.blockchain)
)
}
}
class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteResponse> {
class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanResponse> {
override fun run(
session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
ScanTask().run(session) { result ->
when (result) {
@ -71,7 +44,7 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
createMissingWalletsIfNeeded(card, session, callback)
} else {
callback(CompletionResult.Success(
ScanNoteResponse(card, session.environment.walletData)))
ScanResponse(card, ProductType.Other, session.environment.walletData)))
}
}
}
@ -80,11 +53,11 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
private fun createMissingWalletsIfNeeded(
card: Card, session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
val walletData = session.environment.walletData
if (card.wallets.isEmpty()) {
callback(CompletionResult.Success(ScanNoteResponse(card, walletData)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData)))
return
}
@ -93,14 +66,14 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
val curvesToCreate = card.supportedCurves.subtract(curvesPresent)
if (curvesToCreate.isEmpty()) {
callback(CompletionResult.Success(ScanNoteResponse(card, walletData)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData)))
return
}
CreateWalletsTask(curvesToCreate.toList()).run(session) { result ->
when (result) {
is CompletionResult.Success ->
callback(CompletionResult.Success(ScanNoteResponse(result.data, walletData)))
callback(CompletionResult.Success(ScanResponse(result.data, ProductType.Other, walletData)))
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
@ -109,34 +82,35 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
private fun dealWithTwinCard(
card: Card, session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
ReadIssuerDataCommand().run(session) { readDataResult ->
when (readDataResult) {
is CompletionResult.Success -> {
val publicKey = card.getSingleWallet()?.publicKey
if (publicKey == null) {
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, null)))
return@run
}
val verified = TwinCardsManager.verifyTwinPublicKey(
readDataResult.data.issuerData, publicKey
readDataResult.data.issuerData, publicKey
)
if (verified) {
val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65)
callback(CompletionResult.Success(
ScanNoteResponse(
card = card,
walletData = session.environment.walletData,
secondTwinPublicKey = twinPublicKey.toHexString())
ScanResponse(
card = card,
ProductType.Other,
walletData = session.environment.walletData,
secondTwinPublicKey = twinPublicKey.toHexString())
))
return@run
} else {
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, null)))
}
}
is CompletionResult.Failure ->
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, null)))
}
}
}

View file

@ -1,6 +1,7 @@
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
@ -9,19 +10,25 @@ import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.wallet.CreateWalletCommand
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.domain.ProductType
import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.tap.domain.TapWorkarounds.isTangemNote
import com.tangem.tap.domain.TapWorkarounds.isTangemWallet
import com.tangem.tap.domain.tasks.product.CreateProductWalletsTask
import com.tangem.tap.domain.tasks.product.ProductCommandProcessor
import com.tangem.tap.domain.twins.isTangemTwin
import com.tangem.tap.domain.tasks.product.getCurvesForNonCreatedWallets
/**
[REDACTED_AUTHOR]
*/
class CreateProductWalletAndRescanTask : CardSessionRunnable<Card> {
class CreateProductWalletAndRescanTask(
private val type: ProductType,
) : CardSessionRunnable<Card> {
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
CreateProductWalletTask().run(session) { result ->
val card = session.environment.card.guard {
callback(CompletionResult.Failure(TangemSdkError.CardError()))
return
}
CreateProductWalletTask(card, type).run(session) { result ->
when (result) {
is CompletionResult.Success -> PreflightReadTask(PreflightReadMode.FullCardRead).run(session, callback)
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
@ -30,18 +37,16 @@ class CreateProductWalletAndRescanTask : CardSessionRunnable<Card> {
}
}
private class CreateProductWalletTask : CardSessionRunnable<CreateWalletResponse> {
private class CreateProductWalletTask(
private val card: Card,
private val type: ProductType,
) : CardSessionRunnable<CreateWalletResponse> {
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
val card = session.environment.card.guard {
callback(CompletionResult.Failure(TangemSdkError.CardError()))
return
}
val commandProcessor = when {
card.isTangemNote() -> CreateWalletTangemNote()
card.isTangemTwin() -> CreateWalletTangemTwin()
card.isTangemWallet() -> CreateWalletTangemWallet()
val commandProcessor = when (type) {
ProductType.Note -> CreateWalletTangemNote()
ProductType.Twin -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
ProductType.Wallet -> CreateWalletTangemWallet()
else -> CreateWalletOtherCards()
}
commandProcessor.proceed(card, session, callback)
@ -86,53 +91,28 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateWalletRes
session: CardSession,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit
) {
throw UnsupportedOperationException()
}
}
private class CreateWalletTangemTwin : ProductCommandProcessor<CreateWalletResponse> {
override fun proceed(
card: Card,
session: CardSession,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit
) {
throw UnsupportedOperationException()
//TODO:
}
}
private class CreateWalletOtherCards : ProductCommandProcessor<CreateWalletResponse> {
private var index = 0
private val curves = EllipticCurve.values().toList()
override fun proceed(
card: Card,
session: CardSession,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit
) {
val curve = curves[index]
createWallet(curve, session, callback)
}
val firmwareVersion = card.firmwareVersion
val task = if (firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
CreateProductWalletsTask(listOf(card.supportedCurves.first()))
} else {
CreateProductWalletsTask(card.getCurvesForNonCreatedWallets())
}
private fun createWallet(
curve: EllipticCurve,
session: CardSession,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit
) {
CreateWalletCommand(curve).run(session) { result ->
task.run(session) { result ->
when (result) {
is CompletionResult.Success -> {
if (index == curves.lastIndex) {
callback(CompletionResult.Success(result.data))
return@run
}
index += 1
createWallet(curves[index], session, callback)
}
is CompletionResult.Failure -> {
callback(CompletionResult.Failure(result.error))
}
is CompletionResult.Success -> callback(CompletionResult.Success(result.data.createWalletResponses[0]))
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}

View file

@ -0,0 +1,49 @@
package com.tangem.tap.domain.tasks.product
import com.tangem.common.CompletionResult
import com.tangem.common.card.EllipticCurve
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.operations.CommandResponse
import com.tangem.operations.wallet.CreateWalletCommand
import com.tangem.operations.wallet.CreateWalletResponse
/**
[REDACTED_AUTHOR]
*/
class CreateProductWalletsResponse(
val createWalletResponses: List<CreateWalletResponse>
) : CommandResponse
class CreateProductWalletsTask(
private val curves: List<EllipticCurve>,
) : CardSessionRunnable<CreateProductWalletsResponse> {
private val createdWalletsResponses = mutableListOf<CreateWalletResponse>()
override fun run(session: CardSession, callback: (result: CompletionResult<CreateProductWalletsResponse>) -> Unit) {
val curve = curves[createdWalletsResponses.size]
createWallet(curve, session, callback)
}
private fun createWallet(
curve: EllipticCurve,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletsResponse>) -> Unit
) {
CreateWalletCommand(curve).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
createdWalletsResponses.add(result.data)
if (createdWalletsResponses.size == curves.size) {
callback(CompletionResult.Success(CreateProductWalletsResponse(createdWalletsResponses)))
return@run
}
createWallet(curves[createdWalletsResponses.size], session, callback)
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
}

View file

@ -1,29 +1,62 @@
package com.tangem.tap.domain.tasks.product
import com.tangem.*
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
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.card.WalletData
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemError
import com.tangem.common.extensions.toHexString
import com.tangem.operations.CommandResponse
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.ScanTask
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.tap.domain.ProductType
import com.tangem.tap.domain.TapSdkError
import com.tangem.tap.domain.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.tap.domain.TapWorkarounds.isExcluded
import com.tangem.tap.domain.TapWorkarounds.isTangemNote
import com.tangem.tap.domain.TapWorkarounds.isTangemWallet
import com.tangem.tap.domain.extensions.getSingleWallet
import com.tangem.tap.domain.tasks.CreateWalletsTask
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.twins.TwinCardsManager
import com.tangem.tap.domain.twins.isTangemTwin
class ScanProductTask(val card: Card? = null) : CardSessionRunnable<ScanNoteResponse> {
data class ScanResponse(
val card: Card,
val productType: ProductType,
val walletData: WalletData?,
val secondTwinPublicKey: String? = null,
) : CommandResponse {
fun getBlockchain(): Blockchain {
if (productType == ProductType.Note) return card.getTangemNoteBlockchain() ?: return Blockchain.Unknown
val blockchainName: String = walletData?.blockchain ?: return Blockchain.Unknown
return Blockchain.fromId(blockchainName)
}
fun getPrimaryToken(): Token? {
val cardToken = walletData?.token ?: return null
return Token(
cardToken.name,
cardToken.symbol,
cardToken.contractAddress,
cardToken.decimals,
Blockchain.fromId(walletData.blockchain)
)
}
}
class ScanProductTask(val card: Card? = null) : CardSessionRunnable<ScanResponse> {
override fun run(
session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
ScanTask().run(session) { result ->
when (result) {
@ -56,38 +89,38 @@ class ScanProductTask(val card: Card? = null) : CardSessionRunnable<ScanNoteResp
}
}
private class ScanNoteProcessor : ProductCommandProcessor<ScanNoteResponse> {
private class ScanNoteProcessor : ProductCommandProcessor<ScanResponse> {
override fun proceed(
card: Card,
session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit
callback: (result: CompletionResult<ScanResponse>) -> Unit
) {
callback(CompletionResult.Success(ScanNoteResponse(card, session.environment.walletData)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Note, session.environment.walletData)))
}
}
private class ScanWalletProcessor : ProductCommandProcessor<ScanNoteResponse> {
private class ScanWalletProcessor : ProductCommandProcessor<ScanResponse> {
override fun proceed(
card: Card,
session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit
callback: (result: CompletionResult<ScanResponse>) -> Unit
) {
callback(CompletionResult.Success(ScanNoteResponse(card, session.environment.walletData)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Wallet, session.environment.walletData)))
}
}
private class ScanTwinProcessor : ProductCommandProcessor<ScanNoteResponse> {
private class ScanTwinProcessor : ProductCommandProcessor<ScanResponse> {
override fun proceed(
card: Card,
session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
ReadIssuerDataCommand().run(session) { readDataResult ->
when (readDataResult) {
is CompletionResult.Success -> {
val publicKey = card.getSingleWallet()?.publicKey
if (publicKey == null) {
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Twin, null)))
return@run
}
val verified = TwinCardsManager.verifyTwinPublicKey(
@ -96,46 +129,62 @@ private class ScanTwinProcessor : ProductCommandProcessor<ScanNoteResponse> {
if (verified) {
val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65)
callback(CompletionResult.Success(
ScanNoteResponse(
card = card,
walletData = session.environment.walletData,
secondTwinPublicKey = twinPublicKey.toHexString())
ScanResponse(
card,
ProductType.Twin,
session.environment.walletData,
twinPublicKey.toHexString())
))
return@run
} else {
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Twin, null)))
}
}
is CompletionResult.Failure ->
callback(CompletionResult.Success(ScanNoteResponse(card, null)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Twin, null)))
}
}
}
}
private class ScanOtherCardsProcessor : ProductCommandProcessor<ScanNoteResponse> {
override fun proceed(card: Card, session: CardSession, callback: (result: CompletionResult<ScanNoteResponse>) -> Unit) {
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()) {
callback(CompletionResult.Success(ScanNoteResponse(card, walletData)))
if (card.wallets.isEmpty() || card.firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData)))
return
}
val curvesPresent = card.wallets.map { it.curve }
val curvesToCreate = card.supportedCurves.subtract(curvesPresent)
val curvesToCreate = card.getCurvesForNonCreatedWallets()
if (curvesToCreate.isEmpty()) {
callback(CompletionResult.Success(ScanNoteResponse(card, walletData)))
callback(CompletionResult.Success(ScanResponse(card, ProductType.Other, walletData)))
return
}
CreateWalletsTask().run(session) { result ->
CreateProductWalletsTask(curvesToCreate).run(session) { result ->
when (result) {
is CompletionResult.Success ->
callback(CompletionResult.Success(ScanNoteResponse(result.data, walletData)))
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)
return curvesForNonCreatedWallets.toList()
}

View file

@ -6,16 +6,16 @@ import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.ScanNoteTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
import com.tangem.tap.domain.tasks.product.ScanResponse
class FinalizeTwinTask(
private val twinPublicKey: ByteArray, private val issuerKeys: KeyPair,
) : CardSessionRunnable<ScanNoteResponse> {
) : CardSessionRunnable<ScanResponse> {
override fun run(
session: CardSession,
callback: (result: CompletionResult<ScanNoteResponse>) -> Unit,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
WriteProtectedIssuerDataTask(twinPublicKey, issuerKeys).run(session) { result ->
when (result) {
@ -23,7 +23,7 @@ class FinalizeTwinTask(
PreflightReadTask(PreflightReadMode.FullCardRead).run(session) { readResult ->
when (readResult) {
is CompletionResult.Success ->
ScanNoteTask(readResult.data).run(session, callback)
ScanProductTask(readResult.data).run(session, callback)
is CompletionResult.Failure ->
callback(CompletionResult.Failure(readResult.error))
}

View file

@ -14,20 +14,20 @@ import com.tangem.common.extensions.toHexString
import com.tangem.crypto.CryptoUtils
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
import com.tangem.tap.common.extensions.readAssetAsString
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.network.createMoshi
import com.tangem.tap.tangemSdkManager
class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context: Context) {
class TwinCardsManager(private val scanResponse: ScanResponse, context: Context) {
private val currentCardId: String = scanNoteResponse.card.cardId
private val currentCardId: String = scanResponse.card.cardId
private val secondCardId: String? = TwinsHelper.getTwinsCardId(currentCardId)
private var currentCardPublicKey: String? = null
private var secondCardPublicKey: String? = null
private val issuerKeyPair: KeyPair = getIssuerKeys(
context, scanNoteResponse.card.issuer.publicKey.toHexString()
context, scanResponse.card.issuer.publicKey.toHexString()
)
suspend fun createFirstWallet(message: Message): SimpleResult {
@ -44,7 +44,7 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context:
FirebaseAnalyticsHandler.logCardSdkError(
error,
FirebaseAnalyticsHandler.ActionToLog.CreateWallet,
card = scanNoteResponse.card
card = scanResponse.card
)
}
return SimpleResult.failure(response.error)
@ -77,7 +77,7 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context:
FirebaseAnalyticsHandler.logCardSdkError(
error,
FirebaseAnalyticsHandler.ActionToLog.CreateWallet,
card = scanNoteResponse.card
card = scanResponse.card
)
}
return SimpleResult.failure(response.error)
@ -86,7 +86,7 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context:
}
suspend fun complete(message: Message): Result<ScanNoteResponse> {
suspend fun complete(message: Message): Result<ScanResponse> {
val response = tangemSdkManager.runTaskAsync(
FinalizeTwinTask(secondCardPublicKey!!.hexToBytes(), issuerKeyPair),
currentCardId, message
@ -98,7 +98,7 @@ class TwinCardsManager(private val scanNoteResponse: ScanNoteResponse, context:
FirebaseAnalyticsHandler.logCardSdkError(
error,
FirebaseAnalyticsHandler.ActionToLog.WriteIssuerData,
card = scanNoteResponse.card
card = scanResponse.card
)
}
Result.failure(response.error)

View file

@ -7,7 +7,7 @@ import com.tangem.common.card.Card
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.tap.common.redux.global.FiatCurrencyName
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.domain.termsOfUse.CardTou
import com.tangem.tap.domain.twins.TwinCardNumber
import com.tangem.tap.features.details.redux.twins.CreateTwinWallet
@ -18,13 +18,13 @@ import org.rekotlin.Action
sealed class DetailsAction : Action {
data class PrepareScreen(
val card: Card,
val scanNoteResponse: ScanNoteResponse,
val wallets: List<Wallet>,
val isCreatingTwinWalletAllowed: Boolean?,
val cardTou: CardTou,
val fiatCurrencyName: FiatCurrencyName,
val fiatCurrencies: List<FiatCurrencyName>? = null,
val card: Card,
val scanResponse: ScanResponse,
val wallets: List<Wallet>,
val isCreatingTwinWalletAllowed: Boolean?,
val cardTou: CardTou,
val fiatCurrencyName: FiatCurrencyName,
val fiatCurrencies: List<FiatCurrencyName>? = null,
) : DetailsAction()
object ShowDisclaimer : DetailsAction()
@ -81,7 +81,7 @@ sealed class DetailsAction : Action {
}
data class LaunchThirdStep(val message: Message) : CreateTwinWalletAction() {
data class Success(val scanNoteResponse: ScanNoteResponse) : CreateTwinWalletAction()
data class Success(val scanResponse: ScanResponse) : CreateTwinWalletAction()
object Failure : CreateTwinWalletAction()
}
}

View file

@ -48,7 +48,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: DetailsState): DetailsState {
val twinsState = if (action.card.isTangemTwin()) {
CreateTwinWalletState(
scanResponse = action.scanNoteResponse,
scanResponse = action.scanResponse,
twinCardNumber = TwinsHelper.getTwinCardNumber(action.card.cardId),
createTwinWallet = null,
showAlert = false,

View file

@ -48,7 +48,7 @@ class CreateTwinWalletMiddleware {
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
}
is DetailsAction.CreateTwinWalletAction.LaunchFirstStep -> {
store.state.globalState.scanNoteResponse?.let {
store.state.globalState.scanResponse?.let {
twinsManager = TwinCardsManager(it, action.context)
}
scope.launch {
@ -106,7 +106,7 @@ class CreateTwinWalletMiddleware {
}
is DetailsAction.CreateTwinWalletAction.LaunchThirdStep.Success -> {
scope.launch {
store.state.globalState.tapWalletManager.onCardScanned(action.scanNoteResponse)
store.state.globalState.tapWalletManager.onCardScanned(action.scanResponse)
}
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))

View file

@ -1,15 +1,15 @@
package com.tangem.tap.features.details.redux.twins
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.domain.twins.TwinCardNumber
data class CreateTwinWalletState(
val scanResponse: ScanNoteResponse?,
val step: CreateTwinWalletStep = CreateTwinWalletStep.FirstStep,
val twinCardNumber: TwinCardNumber?,
val createTwinWallet: CreateTwinWallet?,
val showAlert: Boolean,
val allowRecreatingWallet: Boolean? = null
val scanResponse: ScanResponse?,
val step: CreateTwinWalletStep = CreateTwinWalletStep.FirstStep,
val twinCardNumber: TwinCardNumber?,
val createTwinWallet: CreateTwinWallet?,
val showAlert: Boolean,
val allowRecreatingWallet: Boolean? = null
)
enum class CreateTwinWalletStep { FirstStep, SecondStep, ThirdStep }

View file

@ -133,7 +133,7 @@ class WalletConnectMiddleware {
private fun handleScanCard(wcUri: String) {
scope.launch {
val result = tangemSdkManager.scanNote(
val result = tangemSdkManager.scanProduct(
FirebaseAnalyticsHandler,
R.string.wallet_connect_scan_card_message
)
@ -174,7 +174,7 @@ class WalletConnectMiddleware {
private fun getWalletManager(card: Card): WalletManager? {
val factory = store.state.globalState.tapWalletManager.walletManagerFactory
return if (store.state.globalState.scanNoteResponse?.card?.cardId == card.cardId) {
return if (store.state.globalState.scanResponse?.card?.cardId == card.cardId) {
store.state.walletState.getWalletManager(Blockchain.Ethereum)
?: factory.makeWalletManagerForApp(card, Blockchain.Ethereum)
?.also { walletManager ->

View file

@ -3,6 +3,7 @@ package com.tangem.tap.features.home.redux
import com.tangem.tap.common.entities.IndeterminateProgressButton
import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.extensions.withMainContext
import com.tangem.tap.common.post
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
@ -10,7 +11,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.features.onboarding.service.OnboardingHelper
import com.tangem.tap.features.send.redux.states.ButtonState
import com.tangem.tap.features.wallet.redux.ProgressState
@ -56,11 +57,11 @@ private fun handleReadCard() {
store.dispatch(HomeAction.ChangeScanCardButtonState(btnState))
}
fun proceedToWalletScreen(tapWalletManager: TapWalletManager, scanResponse: ScanNoteResponse) {
changeButtonState(ButtonState.ENABLED)
fun proceedToWalletScreen(tapWalletManager: TapWalletManager, scanResponse: ScanResponse) {
scope.launch {
tapWalletManager.onCardScanned(scanResponse)
delay(DELAY_SDK_DIALOG_CLOSE)
withMainContext { changeButtonState(ButtonState.ENABLED) }
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
}
}

View file

@ -19,6 +19,7 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.layout_onboarding_bottom_action_views.*
import kotlinx.android.synthetic.main.layout_onboarding_note.*
import kotlinx.android.synthetic.main.view_onboarding_progress.*
import kotlinx.android.synthetic.main.view_onboarding_tv_balance.*
/**
@ -50,6 +51,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
oldState.onboardingNoteState == newState.onboardingNoteState
}.select { it.onboardingNoteState }
}
storeSubscribersList.add(this)
}
override fun newState(state: OnboardingNoteState) {
@ -147,7 +149,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
tv_body.setText(R.string.onboarding_done_body)
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8))
updateConstraints(R.layout.lp_onboarding_done)
updateConstraints(R.layout.lp_onboarding_done_activation)
}
private fun updateConstraints(@LayoutRes layoutId: Int) {

View file

@ -54,7 +54,7 @@ private fun handleNoteAction(action: Action) {
}
is OnboardingNoteAction.CreateWallet -> {
scope.launch {
val result = tangemSdkManager.createProductWallet(service.scanResponse.card.cardId)
val result = tangemSdkManager.createProductWallet(service.scanResponse)
withMainContext {
when (result) {
is CompletionResult.Success -> {

View file

@ -32,6 +32,7 @@ class OnboardingWalletFragment : BaseStoreFragment(R.layout.fragment_onboarding_
oldState.onboardingWalletState == newState.onboardingWalletState
}.select { it.onboardingWalletState }
}
storeSubscribersList.add(this)
}
override fun newState(state: OnboardingWalletState) {

View file

@ -2,9 +2,9 @@ package com.tangem.tap.features.onboarding.service
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.domain.TapWorkarounds.isTangemNote
import com.tangem.tap.domain.ProductType
import com.tangem.tap.domain.extensions.hasWallets
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.preferencesStorage
/**
@ -13,20 +13,20 @@ import com.tangem.tap.preferencesStorage
class OnboardingHelper {
companion object {
fun isOnboardingCase(response: ScanNoteResponse): Boolean = if (response.card.hasWallets())
fun isOnboardingCase(response: ScanResponse): Boolean = if (response.card.hasWallets())
preferencesStorage.usedCardsPrefStorage.activationIsStarted(response.card.cardId) else true
fun createService(
fromScreen: AppScreen,
scanResponse: ScanNoteResponse,
scanResponse: ScanResponse,
walletManagerFactory: WalletManagerFactory,
): ProductOnboardingService? {
val card = scanResponse.card
val cardInfoStorage = preferencesStorage.usedCardsPrefStorage
return when {
card.isTangemNote() -> OnboardingNoteService(fromScreen, scanResponse, cardInfoStorage,
walletManagerFactory)
else -> null
return when(scanResponse.productType) {
ProductType.Note -> OnboardingNoteService(fromScreen, scanResponse, cardInfoStorage, walletManagerFactory)
ProductType.Wallet -> null
ProductType.Twin -> null
ProductType.Other -> OnboardingOtherCardsService(fromScreen, scanResponse, cardInfoStorage, walletManagerFactory)
}
}
}

View file

@ -2,7 +2,7 @@ package com.tangem.tap.features.onboarding.service
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.persistence.UsedCardsPrefStorage
/**
@ -10,7 +10,7 @@ import com.tangem.tap.persistence.UsedCardsPrefStorage
*/
class OnboardingNoteService(
override val fromScreen: AppScreen,
override var scanResponse: ScanNoteResponse,
override var scanResponse: ScanResponse,
cardInfoStorage: UsedCardsPrefStorage,
walletManagerFactory: WalletManagerFactory,
) : ProductOnboardingService(cardInfoStorage, walletManagerFactory) {

View file

@ -16,7 +16,7 @@ import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.UrlBitmapLoader
import com.tangem.tap.domain.extensions.getArtworkUrl
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.domain.topup.TradeCryptoHelper
import com.tangem.tap.features.wallet.redux.AddressData
import com.tangem.tap.features.wallet.redux.Artwork
@ -37,7 +37,7 @@ import kotlin.coroutines.suspendCoroutine
*/
interface OnboardingService {
val fromScreen: AppScreen
val scanResponse: ScanNoteResponse
val scanResponse: ScanResponse
// val cardInfoStorage: UsedCardsPrefStorage
var walletManager: WalletManager?
@ -141,7 +141,7 @@ abstract class ProductOnboardingService(
val walletManager = walletManager ?: walletManagerFactory.makePrimaryWalletManager(scanResponse).guard {
val customError = TapError.CustomError("Loading cancelled. Cause: wallet manager didn't created")
loadedBalance = OnboardingWalletBalance.error(customError)
withMainContext { loadedBalance = OnboardingWalletBalance.error(customError) }
return loadedBalance
}
@ -178,7 +178,6 @@ abstract class ProductOnboardingService(
override fun activationStarted() {
cardInfoStorage.activationStarted(scanResponse.card.cardId)
}
override fun activationFinished() {

View file

@ -21,9 +21,9 @@ import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.extensions.minimalAmount
import com.tangem.tap.features.send.redux.*
import com.tangem.tap.features.send.redux.FeeAction.RequestFee
import com.tangem.tap.features.send.redux.states.ButtonState
import com.tangem.tap.features.send.redux.states.ExternalTransactionData
import com.tangem.tap.features.send.redux.states.MainCurrencyType
import com.tangem.tap.features.send.redux.states.ButtonState
import com.tangem.tap.features.send.redux.states.TransactionExtrasState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.scope
@ -77,7 +77,7 @@ private fun verifyAndSendTransaction(
) {
val sendState = appState?.sendState ?: return
val walletManager = sendState.walletManager ?: return
val card = appState.globalState.scanNoteResponse?.card ?: return
val card = appState.globalState.scanResponse?.card ?: return
val destinationAddress = sendState.addressPayIdState.destinationWalletAddress ?: return
val typedAmount = sendState.amountState.amountToExtract ?: return
val feeAmount = sendState.feeState.currentFee ?: return

View file

@ -14,7 +14,7 @@ class TokensMiddleware {
{ action ->
when (action) {
is TokensAction.LoadCurrencies -> {
val card = state()?.globalState?.scanNoteResponse?.card
val card = state()?.globalState?.scanResponse?.card
val isTestcard = card?.isTestCard ?: false
val tokens = currenciesRepository.getPopularTokens(isTestcard)
val blockchains = currenciesRepository.getBlockchains(

View file

@ -8,7 +8,6 @@ import com.tangem.tap.common.redux.global.GlobalState
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.currenciesRepository
import com.tangem.tap.domain.TapWorkarounds.isTestCard
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
import com.tangem.tap.domain.extensions.makeWalletManagersForApp
import com.tangem.tap.features.wallet.redux.Currency
@ -36,7 +35,7 @@ class MultiWalletMiddleware {
}
}
is WalletAction.MultiWallet.AddToken -> {
globalState?.scanNoteResponse?.card?.cardId?.let {
globalState?.scanResponse?.card?.cardId?.let {
currenciesRepository.saveAddedToken(it, action.token)
}
addToken(action.token, walletState, globalState)
@ -45,7 +44,7 @@ class MultiWalletMiddleware {
addTokens(action.tokens, walletState, globalState)
}
is WalletAction.MultiWallet.AddBlockchain -> {
globalState?.scanNoteResponse?.card?.let { card ->
globalState?.scanResponse?.card?.let { card ->
currenciesRepository.saveAddedBlockchain(card.cardId, action.blockchain)
if (walletState?.blockchains?.contains(action.blockchain) != true) {
globalState.tapWalletManager.walletManagerFactory
@ -58,11 +57,11 @@ class MultiWalletMiddleware {
store.dispatch(WalletAction.LoadWallet(blockchain = action.blockchain))
}
is WalletAction.MultiWallet.SaveCurrencies -> {
val cardId = globalState?.scanNoteResponse?.card?.cardId
val cardId = globalState?.scanResponse?.card?.cardId
cardId?.let { currenciesRepository.saveCardCurrencies(it, action.cardCurrencies) }
}
is WalletAction.MultiWallet.RemoveWallet -> {
val cardId = globalState?.scanNoteResponse?.card?.cardId
val cardId = globalState?.scanResponse?.card?.cardId
when (val currency = action.walletData.currency) {
is Currency.Blockchain -> {
cardId?.let {
@ -80,7 +79,7 @@ class MultiWalletMiddleware {
}
}
is WalletAction.MultiWallet.FindBlockchainsInUse -> {
val cardFirmware = globalState?.scanNoteResponse?.card?.firmwareVersion
val cardFirmware = globalState?.scanResponse?.card?.firmwareVersion
val blockchains = currenciesRepository.getBlockchains(cardFirmware)
.filterNot { walletState?.blockchains?.contains(it) == true }
val walletManagers =
@ -117,7 +116,7 @@ class MultiWalletMiddleware {
}
}
is WalletAction.MultiWallet.FindTokensInUse -> {
val card = globalState?.scanNoteResponse?.card ?: return
val card = globalState?.scanResponse?.card ?: return
val walletManager = walletState?.getWalletManager(Blockchain.Ethereum)
?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(
card = card,
@ -156,7 +155,7 @@ class MultiWalletMiddleware {
}
private fun addToken(token: Token, walletState: WalletState?, globalState: GlobalState?) {
val card = globalState?.scanNoteResponse?.card ?: return
val card = globalState?.scanResponse?.card ?: return
val walletManager = walletState?.getWalletManager(token)
?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(
card = card,
@ -186,7 +185,7 @@ class MultiWalletMiddleware {
walletState: WalletState?,
globalState: GlobalState?,
) {
val card = globalState?.scanNoteResponse?.card ?: return
val card = globalState?.scanResponse?.card ?: return
val tokensWithManagers = tokens.map { token ->
val walletManager = walletState?.getWalletManager(token)
?: globalState.tapWalletManager.walletManagerFactory.makeWalletManagerForApp(

View file

@ -96,7 +96,7 @@ class WalletMiddleware {
is WalletAction.CreateWallet -> {
if (walletState?.twinCardsState != null) {
store.dispatch(DetailsAction.CreateTwinWalletAction.ShowWarning(
globalState?.scanNoteResponse?.card?.cardId?.let {
globalState?.scanResponse?.card?.cardId?.let {
TwinsHelper.getTwinCardNumber(it)
},
CreateTwinWallet.CreateWallet
@ -104,12 +104,12 @@ class WalletMiddleware {
} else {
scope.launch {
val result = tangemSdkManager.createWallet(
globalState?.scanNoteResponse?.card?.cardId
globalState?.scanResponse?.card?.cardId
)
when (result) {
is CompletionResult.Success -> {
val scanNoteResponse =
globalState?.scanNoteResponse?.copy(card = result.data)
globalState?.scanResponse?.copy(card = result.data)
scanNoteResponse?.let {
globalState.tapWalletManager.onCardScanned(scanNoteResponse)
}
@ -146,7 +146,7 @@ class WalletMiddleware {
}
is WalletAction.Scan -> {
scope.launch {
val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler)
val result = tangemSdkManager.scanProduct(FirebaseAnalyticsHandler)
scope.launch(Dispatchers.Main) {
store.dispatch(GlobalAction.ScanFailsCounter.ChooseBehavior(result))
when (result) {
@ -186,7 +186,7 @@ class WalletMiddleware {
}
is WalletAction.LoadData -> {
scope.launch {
val scanNoteResponse = globalState?.scanNoteResponse
val scanNoteResponse = globalState?.scanResponse
?: return@launch
if (!walletState?.wallets.isNullOrEmpty()) {
globalState.tapWalletManager.reloadData(scanNoteResponse)
@ -196,7 +196,7 @@ class WalletMiddleware {
}
}
is NetworkStateChanged -> {
globalState?.scanNoteResponse?.let { scanNoteResponse ->
globalState?.scanResponse?.let { scanNoteResponse ->
store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline)
scope.launch {
globalState.tapWalletManager.loadData(scanNoteResponse)

View file

@ -40,7 +40,7 @@ class WarningsMiddleware {
}
is WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline -> checkHashesCountOnline()
is WalletAction.Warnings.CheckHashesCount.SaveCardId -> {
val cardId = globalState?.scanNoteResponse?.card?.cardId
val cardId = globalState?.scanResponse?.card?.cardId
cardId?.let { preferencesStorage.usedCardsPrefStorage.scanned(it) }
}
is WalletAction.Warnings.AppRating.RemindLater -> {
@ -81,7 +81,7 @@ class WarningsMiddleware {
}
private fun showCardWarningsIfNeeded(globalState: GlobalState?) {
globalState?.scanNoteResponse?.card?.let { card ->
globalState?.scanResponse?.card?.let { card ->
globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local)
if (card.isTestCard) {
addWarningMessage(WarningMessagesManager.testCardWarning(), autoUpdate = true)
@ -149,7 +149,7 @@ class WarningsMiddleware {
if (store.state.walletState.hashesCountVerified != false) return
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) return
val card = store.state.globalState.scanNoteResponse?.card
val card = store.state.globalState.scanResponse?.card
if (card == null || preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) return
if (card.isTangemTwin() || card.isMultiwalletAllowed) return

View file

@ -156,7 +156,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
return when (item.itemId) {
R.id.details_menu -> {
store.dispatch(GlobalAction.UpdateFeedbackInfo(store.state.walletState.walletManagers))
store.state.globalState.scanNoteResponse?.let { scanNoteResponse ->
store.state.globalState.scanResponse?.let { scanNoteResponse ->
store.dispatch(DetailsAction.PrepareScreen(
scanNoteResponse.card, scanNoteResponse,
store.state.walletState.walletManagers.map { it.wallet },