Updated on 2026-08-14
This commit is contained in:
parent
08f86f4d52
commit
de501988d0
15 changed files with 148 additions and 17 deletions
|
|
@ -7,10 +7,13 @@ import com.squareup.moshi.JsonClass
|
|||
data class CardActivationRemoteStateResponse(
|
||||
@Json(name = "activation_status") val status: String,
|
||||
@Json(name = "activation_order") val activationOrder: ActivationOrder?,
|
||||
@Json(name = "stepChangeCode") val stepChangeCode: Int?,
|
||||
@Json(name = "updatedAt") val updatedAt: String?,
|
||||
) {
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ActivationOrder(
|
||||
@Json(name = "id") val id: String,
|
||||
@Json(name = "customer_id") val customerId: String,
|
||||
@Json(name = "customer_wallet_address") val customerWalletAddress: String,
|
||||
)
|
||||
}
|
||||
|
|
@ -109,6 +109,8 @@
|
|||
<string name="common_claim_rewards">報酬を受け取る</string>
|
||||
<string name="common_close">閉じる</string>
|
||||
<string name="common_confirm">確認</string>
|
||||
<string name="common_contact_tangem_support">Tangemサポートへ問い合わせる</string>
|
||||
<string name="common_contact_visa_support">Visaサポートへ問い合わせる</string>
|
||||
<string name="common_continue">続ける</string>
|
||||
<string name="common_copy">コピー</string>
|
||||
<string name="common_copy_address">アドレスをコピー</string>
|
||||
|
|
@ -515,6 +517,7 @@
|
|||
<string name="nft_details_token_standard">トークン標準</string>
|
||||
<string name="nft_details_traits">特徴</string>
|
||||
<string name="nft_empty_search">結果がありません。別のリクエストをお試しください。</string>
|
||||
<string name="nft_receive_choose_network">ネットワークを選択</string>
|
||||
<string name="nft_receive_subtitle">私のウォレットへ</string>
|
||||
<string name="nft_receive_title">NFTを受け取る</string>
|
||||
<string name="nft_wallet_count">%1$dコレクションの%2$dNFT</string>
|
||||
|
|
@ -1031,12 +1034,14 @@
|
|||
<string name="visa_onboarding_in_progress_description">長くはかかりません。アカウントを設定しています。</string>
|
||||
<string name="visa_onboarding_in_progress_issuer_description">長くはかかりません。アクティベーションを完了しています。</string>
|
||||
<string name="visa_onboarding_in_progress_title">準備完了です!</string>
|
||||
<string name="visa_onboarding_pin_not_accepted">PINの認証に失敗しました。もう一度お試しいただくか、別のコードを使用してください。</string>
|
||||
<string name="visa_onboarding_pin_validation_error_message">無効な暗証番号:連続や繰り返しを避けてください</string>
|
||||
<string name="visa_onboarding_wallet_connect_title">ウェブサイトに移動</string>
|
||||
<string name="visa_onboarding_welcome_back_description">アカウントの設定を続けましょう。</string>
|
||||
<string name="visa_onboarding_welcome_back_title">お帰りなさい!</string>
|
||||
<string name="visa_onboarding_welcome_description">手順に従ってアカウントを設定してください。</string>
|
||||
<string name="visa_onboarding_welcome_title">ようこそ!</string>
|
||||
<string name="visa_tx_dispute_button">この取引に異議を唱える</string>
|
||||
<string name="visa_unlock_notification_button">ロック解除</string>
|
||||
<string name="visa_unlock_notification_subtitle">カードをスキャンしてアクセスロックを解除する</string>
|
||||
<string name="visa_unlock_notification_title">ロック解除が必要</string>
|
||||
|
|
|
|||
|
|
@ -1020,6 +1020,7 @@
|
|||
<string name="user_wallet_list_rename_popup_title">Переименование кошелька</string>
|
||||
<string name="user_wallet_list_unlock_all">Разблокировать все</string>
|
||||
<string name="user_wallet_list_unlock_all_with">Разблокировать все с %s</string>
|
||||
<string name="visa_onboarding_pin_not_accepted">ПИН не принят. Попробуйте ещё раз или введите другой код.</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">Блокчейн недоступен. Попробуйте позже.</string>
|
||||
<string name="wallet_balance_missing_derivation">Отсканируйте карту или кольцо</string>
|
||||
<string name="wallet_been_activated_message">Этот кошелек уже был активирован ранее.\nЕсли это сделали не вы, свяжитесь со службой поддержки.\nTangem никогда не продает кошелек вместе с предустановленным кодом доступа.</string>
|
||||
|
|
|
|||
|
|
@ -528,11 +528,11 @@
|
|||
<string name="nft_receive_choose_network">Choose network</string>
|
||||
<string name="nft_receive_subtitle">To My wallet</string>
|
||||
<string name="nft_receive_title">Receive NFT</string>
|
||||
<string name="nft_traits_title">Traits</string>
|
||||
<string name="nft_wallet_count">%1$d NFTs in %2$d collection</string>
|
||||
<string name="nft_wallet_receive_nft">Tap here to receive first NFT</string>
|
||||
<string name="nft_wallet_title">NFT collections</string>
|
||||
<string name="nft_wallet_unable_to_load">Unable to load the data</string>
|
||||
<string name="nft_traits_title">Traits</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Set up a single access code to protect all your devices.</string>
|
||||
<string name="onboarding_access_code_feature_1_title">Protect</string>
|
||||
<string name="onboarding_access_code_feature_2_description">Set an individual access code for each card or ring later.</string>
|
||||
|
|
@ -1070,6 +1070,7 @@
|
|||
<string name="visa_onboarding_pin_code_description">Set up a 4-digit code.
It will be used for payments.</string>
|
||||
<string name="visa_onboarding_pin_code_navigation_title">PIN code</string>
|
||||
<string name="visa_onboarding_pin_code_title">Create PIN Code</string>
|
||||
<string name="visa_onboarding_pin_not_accepted">PIN was not accepted. Try again or use a different code.</string>
|
||||
<string name="visa_onboarding_pin_validation_error_message">Invalid PIN: avoid sequences or repeats</string>
|
||||
<string name="visa_onboarding_success_screen_description">You\'re good to go!</string>
|
||||
<string name="visa_onboarding_tangem_approve_description">Prepare the Tangem card and tap to approve</string>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,60 @@
|
|||
package com.tangem.data.visa.converter
|
||||
|
||||
import com.tangem.datasource.api.visa.models.response.CardActivationRemoteStateResponse
|
||||
import com.tangem.domain.visa.model.VisaActivationOrderInfo
|
||||
import com.tangem.domain.visa.model.VisaActivationRemoteState
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class VisaActivationStatusConverter @Inject constructor() :
|
||||
Converter<CardActivationRemoteStateResponse, VisaActivationRemoteState> {
|
||||
|
||||
private val lastUpdatedAt = MutableStateFlow<String?>(null)
|
||||
|
||||
override fun convert(value: CardActivationRemoteStateResponse): VisaActivationRemoteState {
|
||||
// handle pin code error
|
||||
// either we entered pin code before with an error (WasError) or after receiving an error (InProgress)
|
||||
if (
|
||||
value.status == Status.AwaitingPin.stringValue &&
|
||||
value.stepChangeCode != null &&
|
||||
value.stepChangeCode == PIN_CODE_VALIDATION_ERROR
|
||||
) {
|
||||
return if (lastUpdatedAt.value != value.updatedAt) {
|
||||
lastUpdatedAt.value == value.updatedAt
|
||||
|
||||
VisaActivationRemoteState.AwaitingPinCode(
|
||||
activationOrderInfo = value.activationOrder!!.convert(),
|
||||
status = VisaActivationRemoteState.AwaitingPinCode.Status.WasError,
|
||||
)
|
||||
} else {
|
||||
VisaActivationRemoteState.AwaitingPinCode(
|
||||
activationOrderInfo = value.activationOrder!!.convert(),
|
||||
status = VisaActivationRemoteState.AwaitingPinCode.Status.InProgress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Will be implemented in the future
|
||||
return VisaActivationRemoteState.Activated
|
||||
}
|
||||
|
||||
private fun CardActivationRemoteStateResponse.ActivationOrder.convert(): VisaActivationOrderInfo {
|
||||
return VisaActivationOrderInfo(
|
||||
orderId = id,
|
||||
customerId = customerId,
|
||||
customerWalletAddress = customerWalletAddress,
|
||||
)
|
||||
}
|
||||
|
||||
private enum class Status(val stringValue: String) {
|
||||
AwaitingPin("AWAITING_PIN"),
|
||||
// TODO complete statuses list when backend is ready
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PIN_CODE_VALIDATION_ERROR = 1000
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,6 @@ import kotlinx.serialization.Serializable
|
|||
@JsonClass(generateAdapter = true)
|
||||
data class VisaActivationOrderInfo(
|
||||
@Json(name = "orderId") val orderId: String,
|
||||
@Json(name = "customer_id") val customerId: String,
|
||||
@Json(name = "customer_wallet_address") val customerWalletAddress: String,
|
||||
@Json(name = "customerId") val customerId: String,
|
||||
@Json(name = "customerWalletAddress") val customerWalletAddress: String,
|
||||
)
|
||||
|
|
@ -20,9 +20,14 @@ sealed class VisaActivationRemoteState {
|
|||
data object PaymentAccountDeploying : VisaActivationRemoteState()
|
||||
|
||||
@Serializable
|
||||
data class WaitingPinCode(
|
||||
data class AwaitingPinCode(
|
||||
val activationOrderInfo: VisaActivationOrderInfo,
|
||||
) : VisaActivationRemoteState()
|
||||
val status: Status,
|
||||
) : VisaActivationRemoteState() {
|
||||
enum class Status {
|
||||
WaitingForPinCode, InProgress, WasError
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object WaitingForActivationFinishing : VisaActivationRemoteState()
|
||||
|
|
@ -43,6 +48,7 @@ class VisaActivationRemoteState_Json(
|
|||
@Json(name = "type") val type: VisaActivationRemoteState_Type,
|
||||
@Json(name = "requestCardWallet") val requestCardWallet: VisaCardWalletDataToSignRequest? = null,
|
||||
@Json(name = "activationOrderInfo") val activationOrderInfo: VisaActivationOrderInfo? = null,
|
||||
@Json(name = "awaiting_pin_code_status") val awaitingPinCodeStatus: AwaitingPinCodeStatus_Type? = null,
|
||||
)
|
||||
|
||||
@Suppress("ClassNaming")
|
||||
|
|
@ -58,6 +64,12 @@ enum class VisaActivationRemoteState_Type {
|
|||
BlockedForActivation,
|
||||
}
|
||||
|
||||
@Suppress("ClassNaming")
|
||||
@JsonClass(generateAdapter = false)
|
||||
enum class AwaitingPinCodeStatus_Type {
|
||||
WaitingForPinCode, InProgress, WasError
|
||||
}
|
||||
|
||||
@Suppress("ClassNaming")
|
||||
class VisaActivationRemoteState_JsonAdapter {
|
||||
|
||||
|
|
@ -70,7 +82,17 @@ class VisaActivationRemoteState_JsonAdapter {
|
|||
VisaActivationRemoteState.CustomerWalletSignatureRequired(value.activationOrderInfo!!)
|
||||
VisaActivationRemoteState_Type.PaymentAccountDeploying -> VisaActivationRemoteState.PaymentAccountDeploying
|
||||
VisaActivationRemoteState_Type.WaitingPinCode ->
|
||||
VisaActivationRemoteState.WaitingPinCode(value.activationOrderInfo!!)
|
||||
VisaActivationRemoteState.AwaitingPinCode(
|
||||
activationOrderInfo = value.activationOrderInfo!!,
|
||||
status = when (value.awaitingPinCodeStatus!!) {
|
||||
AwaitingPinCodeStatus_Type.WaitingForPinCode ->
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.WaitingForPinCode
|
||||
AwaitingPinCodeStatus_Type.InProgress ->
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.InProgress
|
||||
AwaitingPinCodeStatus_Type.WasError ->
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.WasError
|
||||
},
|
||||
)
|
||||
VisaActivationRemoteState_Type.WaitingForActivationFinishing ->
|
||||
VisaActivationRemoteState.WaitingForActivationFinishing
|
||||
VisaActivationRemoteState_Type.Activated -> VisaActivationRemoteState.Activated
|
||||
|
|
@ -93,10 +115,18 @@ class VisaActivationRemoteState_JsonAdapter {
|
|||
)
|
||||
is VisaActivationRemoteState.PaymentAccountDeploying ->
|
||||
VisaActivationRemoteState_Json(VisaActivationRemoteState_Type.PaymentAccountDeploying)
|
||||
is VisaActivationRemoteState.WaitingPinCode ->
|
||||
is VisaActivationRemoteState.AwaitingPinCode ->
|
||||
VisaActivationRemoteState_Json(
|
||||
VisaActivationRemoteState_Type.WaitingPinCode,
|
||||
activationOrderInfo = value.activationOrderInfo,
|
||||
awaitingPinCodeStatus = when (value.status) {
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.WaitingForPinCode ->
|
||||
AwaitingPinCodeStatus_Type.WaitingForPinCode
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.InProgress ->
|
||||
AwaitingPinCodeStatus_Type.InProgress
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.WasError ->
|
||||
AwaitingPinCodeStatus_Type.WasError
|
||||
},
|
||||
)
|
||||
is VisaActivationRemoteState.WaitingForActivationFinishing ->
|
||||
VisaActivationRemoteState_Json(VisaActivationRemoteState_Type.WaitingForActivationFinishing)
|
||||
|
|
|
|||
|
|
@ -167,7 +167,9 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
params = OnboardingVisaOtherWalletComponent.Params(
|
||||
childParams = childParams,
|
||||
onDone = {
|
||||
model.stackNavigation.pushNew(OnboardingVisaRoute.PinCode(activationOrderInfo = it))
|
||||
model.stackNavigation.pushNew(
|
||||
OnboardingVisaRoute.PinCode(activationOrderInfo = it, pinCodeValidationError = false),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
@ -176,6 +178,7 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
|
|||
config = OnboardingVisaPinCodeComponent.Config(
|
||||
scanResponse = model.currentScanResponse.value,
|
||||
activationOrderInfo = route.activationOrderInfo,
|
||||
wasValidationError = route.pinCodeValidationError,
|
||||
),
|
||||
params = OnboardingVisaPinCodeComponent.Params(
|
||||
childParams = childParams,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
_uiState.update {
|
||||
it.copy(
|
||||
accessCodeFirst = textFieldValue,
|
||||
accessCodeSecond = TextFieldValue(),
|
||||
atLeastMinCharsError = false,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,9 +75,10 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
VisaActivationRemoteState.WaitingForActivationFinishing,
|
||||
-> {
|
||||
}
|
||||
is VisaActivationRemoteState.WaitingPinCode -> {
|
||||
navigateToPinCode(result.activationOrderInfo)
|
||||
return@launch
|
||||
is VisaActivationRemoteState.AwaitingPinCode -> {
|
||||
navigateToPinCodeIfNeeded(result) {
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
VisaActivationRemoteState.Activated -> {
|
||||
finishActivation()
|
||||
|
|
@ -90,8 +91,37 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun navigateToPinCode(activationOrderInfo: VisaActivationOrderInfo) {
|
||||
onDone.emit(Params.DoneEvent.NavigateTo(OnboardingVisaRoute.PinCode(activationOrderInfo)))
|
||||
private suspend inline fun navigateToPinCodeIfNeeded(
|
||||
remoteState: VisaActivationRemoteState.AwaitingPinCode,
|
||||
returnBlock: () -> Unit,
|
||||
) {
|
||||
when (remoteState.status) {
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.WaitingForPinCode -> {
|
||||
onDone.emit(
|
||||
Params.DoneEvent.NavigateTo(
|
||||
OnboardingVisaRoute.PinCode(
|
||||
activationOrderInfo = remoteState.activationOrderInfo,
|
||||
pinCodeValidationError = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
returnBlock()
|
||||
}
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.WasError -> {
|
||||
onDone.emit(
|
||||
Params.DoneEvent.NavigateTo(
|
||||
OnboardingVisaRoute.PinCode(
|
||||
activationOrderInfo = remoteState.activationOrderInfo,
|
||||
pinCodeValidationError = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
returnBlock()
|
||||
}
|
||||
VisaActivationRemoteState.AwaitingPinCode.Status.InProgress -> {
|
||||
/** waiting for new state */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun finishActivation() {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
|||
visaActivationRepository.getActivationRemoteStateLongPoll()
|
||||
}.getOrNull()
|
||||
|
||||
if (result is VisaActivationRemoteState.WaitingPinCode) {
|
||||
if (result is VisaActivationRemoteState.AwaitingPinCode) {
|
||||
onDone.emit(result.activationOrderInfo)
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ internal class OnboardingVisaPinCodeComponent(
|
|||
data class Config(
|
||||
val scanResponse: ScanResponse,
|
||||
val activationOrderInfo: VisaActivationOrderInfo,
|
||||
val wasValidationError: Boolean,
|
||||
)
|
||||
|
||||
data class Params(
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@ internal class OnboardingVisaPinCodeModel @Inject constructor(
|
|||
submitButtonEnabled = false,
|
||||
onPinCodeChange = ::onPinCodeChange,
|
||||
onSubmitClick = ::onSubmitClick,
|
||||
error = if (params.wasValidationError) {
|
||||
resourceReference(R.string.visa_onboarding_pin_not_accepted)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -159,8 +159,11 @@ internal class OnboardingVisaModel @Inject constructor(
|
|||
VisaActivationRemoteState.WaitingForActivationFinishing -> {
|
||||
OnboardingVisaRoute.InProgress(from = OnboardingVisaRoute.InProgress.From.PinCode)
|
||||
}
|
||||
is VisaActivationRemoteState.WaitingPinCode -> {
|
||||
OnboardingVisaRoute.PinCode(activationOrderInfo = remoteState.activationOrderInfo)
|
||||
is VisaActivationRemoteState.AwaitingPinCode -> {
|
||||
OnboardingVisaRoute.PinCode(
|
||||
activationOrderInfo = remoteState.activationOrderInfo,
|
||||
pinCodeValidationError = false,
|
||||
)
|
||||
}
|
||||
VisaActivationRemoteState.Activated,
|
||||
VisaActivationRemoteState.BlockedForActivation,
|
||||
|
|
|
|||
|
|
@ -48,5 +48,8 @@ internal sealed class OnboardingVisaRoute {
|
|||
}
|
||||
|
||||
@Serializable
|
||||
data class PinCode(val activationOrderInfo: VisaActivationOrderInfo) : OnboardingVisaRoute()
|
||||
data class PinCode(
|
||||
val activationOrderInfo: VisaActivationOrderInfo,
|
||||
val pinCodeValidationError: Boolean,
|
||||
) : OnboardingVisaRoute()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue