Updated on 2026-08-14

This commit is contained in:
Tangem 2022-10-23 00:51:16 +05:00
parent b8e40c6e73
commit a0e708e46f
25 changed files with 333 additions and 147 deletions

@ -1 +1 @@
Subproject commit c8f577f2ab48e0d6c49f79b6cff21eabe67cd63e
Subproject commit cf6ea50867477f97655da9da47ff94987e8f3354

View file

@ -54,7 +54,6 @@ class DialogManager : StoreSubscriber<GlobalState> {
store.unsubscribe(this)
}
override fun newState(state: GlobalState) {
if (state.dialog == null) {
dialog?.dismiss()
@ -67,6 +66,8 @@ class DialogManager : StoreSubscriber<GlobalState> {
dialog = when (state.dialog) {
is AppDialog.SimpleOkDialog -> SimpleOkDialog.create(state.dialog, context)
is AppDialog.SimpleOkDialogRes -> SimpleOkDialog.create(state.dialog, context)
is AppDialog.SimpleOkErrorDialog -> SimpleOkDialog.create(state.dialog, context)
is AppDialog.SimpleOkWarningDialog -> SimpleOkDialog.create(state.dialog, context)
is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context)
is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context)
is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context)
@ -76,16 +77,16 @@ class DialogManager : StoreSubscriber<GlobalState> {
SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_scanner_error_no_ethereum_wallet,
context = context
context = context,
)
is WalletConnectDialog.AddNetwork ->
SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
message = context.getString(
R.string.wallet_connect_network_not_found_format,
state.dialog.network
state.dialog.network,
),
context = context
context = context,
)
is WalletConnectDialog.OpeningSessionRejected -> {
SimpleAlertDialog.create(
@ -123,7 +124,7 @@ class DialogManager : StoreSubscriber<GlobalState> {
SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_scanner_error_unsupported_network,
context = context
context = context,
)
is BackupDialog.AddMoreBackupCards -> AddMoreBackupCardsDialog.create(context)
is BackupDialog.BackupInProgress -> BackupInProgressDialog.create(context)
@ -142,7 +143,7 @@ class DialogManager : StoreSubscriber<GlobalState> {
is WalletDialog.TokensAreLinkedDialog -> SimpleAlertDialog.create(
title = context.getString(state.dialog.titleRes, state.dialog.currencySymbol),
message = context.getString(
state.dialog.messageRes, state.dialog.currencySymbol, state.dialog.currencyTitle
state.dialog.messageRes, state.dialog.currencySymbol, state.dialog.currencyTitle,
),
context = context,
)
@ -151,7 +152,7 @@ class DialogManager : StoreSubscriber<GlobalState> {
messageRes = state.dialog.messageRes,
context = context,
primaryButtonRes = state.dialog.primaryButtonRes,
primaryButtonAction = state.dialog.onOk
primaryButtonAction = state.dialog.onOk,
)
is WalletDialog.RussianCardholdersWarningDialog ->
RussianCardholdersWarningBottomSheetDialog(context)

View file

@ -0,0 +1,11 @@
package com.tangem.tap.common.extensions
import android.widget.ImageView
import androidx.annotation.DrawableRes
/**
[REDACTED_AUTHOR]
*/
fun ImageView.setDrawable(@DrawableRes resId: Int) {
setImageDrawable(context.getDrawableCompat(resId))
}

View file

@ -12,10 +12,12 @@ interface StateDialog
sealed class AppDialog : StateDialog {
data class SimpleOkDialog(val header: String, val message: String, val onOk: VoidCallback? = null) : AppDialog()
data class SimpleOkErrorDialog(val message: String, val onOk: VoidCallback? = null) : AppDialog()
data class SimpleOkWarningDialog(val message: String, val onOk: VoidCallback? = null) : AppDialog()
data class SimpleOkDialogRes(
val headerId: Int,
val messageId: Int,
val onOk: VoidCallback? = null
val onOk: VoidCallback? = null,
) : AppDialog()
object ScanFailsDialog : AppDialog()
@ -25,6 +27,6 @@ sealed class AppDialog : StateDialog {
) : AppDialog()
data class TestActionsDialog(
val actionsList: List<TestAction>
val actionsList: List<TestAction>,
) : AppDialog()
}

View file

@ -10,7 +10,6 @@ import com.tangem.tap.common.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.AnalyticsParam
import com.tangem.tap.common.analytics.GetCardSourceParams
import com.tangem.tap.common.entities.IndeterminateProgressButton
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.extensions.onCardScanned
@ -28,8 +27,7 @@ import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.OnboardingSaltPayHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog
import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayRegistrationError
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayExceptionHandler
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayAction
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState
import com.tangem.tap.features.send.redux.states.ButtonState
@ -130,20 +128,7 @@ private fun onScanSuccess(scanResponse: ScanResponse) {
}
is Result.Failure -> {
changeButtonState(ButtonState.ENABLED)
when (val error = result.error) {
is SaltPayRegistrationError -> {
val dialog = when (error) {
is SaltPayRegistrationError.NoGas -> SaltPayDialog.NoFundsForActivation
else -> SaltPayDialog.RegistrationError(error)
}
store.dispatchDialogShow(dialog)
}
else -> {
store.dispatchDebugErrorNotification(
error.localizedMessage ?: "SaltPay: Unknown error",
)
}
}
SaltPayExceptionHandler.handle(result.error)
}
}
}

View file

@ -16,7 +16,7 @@ class OnboardingSaltPayHelper {
suspend fun isOnboardingCase(
scanResponse: ScanResponse,
manager: SaltPayRegistrationManager
manager: SaltPayRegistrationManager,
): Result<Boolean> {
return try {
val status = manager.updateSaltPayStatus(
@ -24,7 +24,7 @@ class OnboardingSaltPayHelper {
step = SaltPayRegistrationStep.None,
).successOr { return it }
val isRegistrationCase = status.step != SaltPayRegistrationStep.ClaimSuccess
val isRegistrationCase = status.step != SaltPayRegistrationStep.Finished
val isBackupCase = scanResponse.card.backupStatus?.isActive == false
Result.Success(isRegistrationCase || isBackupCase)
} catch (ex: Exception) {

View file

@ -20,7 +20,6 @@ import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.extensions.hasWallets
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.onboarding.WalletBalanceFetcher
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.scope
@ -130,7 +129,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
store.dispatch(OnboardingNoteAction.Balance.Set(balanceIsLoading))
scope.launch {
val loadedBalance = WalletBalanceFetcher().updateBalance(walletManager)
val loadedBalance = onboardingManager.updateBalance(walletManager)
delay(if (isLoadedBefore) 0 else 300)
loadedBalance.criticalError?.let { store.dispatchErrorNotification(it) }
withMainContext {

View file

@ -30,7 +30,7 @@ data class OnboardingWalletState(
}
fun getMaxProgress(): Int = when {
isSaltPay -> 14
isSaltPay -> 12
else -> 6
}
@ -54,12 +54,12 @@ data class OnboardingWalletState(
SaltPayRegistrationStep.None, SaltPayRegistrationStep.NoGas -> 0
SaltPayRegistrationStep.NeedPin -> 7
SaltPayRegistrationStep.CardRegistration -> 8
SaltPayRegistrationStep.KycIntro -> 9
SaltPayRegistrationStep.KycStart -> 10
SaltPayRegistrationStep.KycWaiting -> 11
SaltPayRegistrationStep.Claim -> 12
SaltPayRegistrationStep.ClaimInProgress -> 13
SaltPayRegistrationStep.ClaimSuccess -> getMaxProgress()
SaltPayRegistrationStep.KycIntro, SaltPayRegistrationStep.KycStart,
SaltPayRegistrationStep.KycWaiting, SaltPayRegistrationStep.KycReject,
-> 9
SaltPayRegistrationStep.Claim -> 10
SaltPayRegistrationStep.ClaimInProgress -> 11
SaltPayRegistrationStep.Finished -> getMaxProgress()
}
}
step == OnboardingWalletStep.Done -> getMaxProgress()

View file

@ -0,0 +1,43 @@
package com.tangem.tap.features.onboarding.products.wallet.saltPay
import com.tangem.common.core.TangemSdkError
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog
import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayRegistrationError
import com.tangem.tap.store
/**
[REDACTED_AUTHOR]
*/
class SaltPayExceptionHandler {
companion object {
fun handle(throwable: Throwable) {
when (throwable) {
is SaltPayRegistrationError -> {
val dialog = when (throwable) {
is SaltPayRegistrationError.NoGas -> SaltPayDialog.NoFundsForActivation
else -> SaltPayDialog.RegistrationError(throwable)
}
store.dispatchDialogShow(dialog)
}
is TangemSdkError -> {
when (throwable) {
is TangemSdkError.NetworkError -> {
val message = (throwable).customMessage
store.dispatchDialogShow(AppDialog.SimpleOkErrorDialog(message))
}
else -> {
// do nothing
}
}
}
else -> {
val message = throwable.message ?: "SaltPay unknown error"
store.dispatchDialogShow(AppDialog.SimpleOkErrorDialog(message))
}
}
}
}
}

View file

@ -4,24 +4,21 @@ import com.tangem.Message
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.extensions.successOr
import com.tangem.common.Filter
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.services.Result
import com.tangem.domain.common.extensions.successOr
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.network.api.paymentology.KYCStatus
import com.tangem.network.api.paymentology.RegistrationResponse
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.TangemSigner
import com.tangem.tap.domain.TapError
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
import com.tangem.tap.features.onboarding.products.wallet.saltPay.AllSymbolsTheSameFilter
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayExceptionHandler
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayRegistrationManager
import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog
import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayRegistrationError
import com.tangem.tap.scope
import com.tangem.tap.store
@ -76,37 +73,9 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App
handleInProgress = false
withMainContext {
// store.dispatch(OnboardingSaltPayAction.SetStep(updateResult.step))
store.dispatch(OnboardingSaltPayAction.SetStep(SaltPayRegistrationStep.KycWaiting))
store.dispatch(OnboardingSaltPayAction.SetStep(updateResult.step))
}
}
// handleIsBusy = true
// scope.launch {
// checkGasIfNeeded(state.saltPayManager, state.step).successOr {
// onException(it.error)
// return@launch
// }
//
// registerKYCIfNeeded(state).successOr {
// onException(it.error)
// return@launch
// }
//
// val amount = getAmountToClaimIfNeeded(state)?.let {
// dispatchOnMain(OnboardingSaltPayAction.SetAmountToClaim(it))
// }
//
// val newStep = checkRegistration(state, amount != null).successOr {
// onException(it.error)
// return@launch
// }
//
// withMainContext {
// handleIsBusy = false
// store.dispatch(OnboardingSaltPayAction.SetStep(newStep))
// }
// }
}
is OnboardingSaltPayAction.RegisterCard -> {
handleInProgress = true
@ -191,7 +160,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App
store.dispatch(OnboardingSaltPayAction.SetPin(action.pin))
store.dispatch(OnboardingSaltPayAction.SetStep(SaltPayRegistrationStep.CardRegistration))
} catch (error: SaltPayRegistrationError) {
handleError = error
SaltPayExceptionHandler.handle(error)
}
}
is OnboardingSaltPayAction.Claim -> {
@ -237,7 +206,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App
val state = getState()
scope.launch {
val balance = state.saltPayManager.getTokenAmount().successOr {
handleException = it.error
SaltPayExceptionHandler.handle(it.error)
handleClaimRefreshInProgress = false
return@launch
}
@ -245,7 +214,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App
handleInProgress = false
handleClaimRefreshInProgress = false
dispatchOnMain(OnboardingSaltPayAction.SetTokenBalance(balance))
dispatchOnMain(OnboardingSaltPayAction.SetStep(SaltPayRegistrationStep.ClaimSuccess))
dispatchOnMain(OnboardingSaltPayAction.SetStep(SaltPayRegistrationStep.Finished))
}
}
else -> {
@ -283,7 +252,7 @@ suspend fun SaltPayRegistrationManager.updateSaltPayStatus(
updateResult = when {
saltPayStep == SaltPayRegistrationStep.Claim && fetchedAmountToClaim == null -> {
updateResult.copy(
step = SaltPayRegistrationStep.ClaimSuccess,
step = SaltPayRegistrationStep.KycReject,
amountToClaim = fetchedAmountToClaim,
)
}
@ -334,51 +303,17 @@ private var handleInProgress: Boolean = false
private suspend fun onError(error: SaltPayRegistrationError) {
withMainContext {
handleInProgress = false
handleError = error
SaltPayExceptionHandler.handle(error)
}
}
private suspend fun onException(error: Throwable) {
withMainContext {
handleInProgress = false
handleException = error
SaltPayExceptionHandler.handle(error)
}
}
private var handleException: Throwable = Throwable("Init")
set(value) {
field = value
when (value) {
is SaltPayRegistrationError -> handleError = value
else -> {
Timber.e(value)
when (value) {
is TangemSdkError -> {
// store.dispatchErrorNotification(TapError.CustomError(value.customMessage))
}
else -> {
store.dispatchErrorNotification(
TapError.CustomError(value.message ?: "Unknown SaltPay exception"),
)
}
}
}
}
}
private var handleError: SaltPayRegistrationError = SaltPayRegistrationError.Unknown
set(value) {
field = value
when (value) {
SaltPayRegistrationError.NoGas -> {
store.dispatch(OnboardingSaltPayAction.SetStep(SaltPayRegistrationStep.NoGas))
}
else -> {
store.dispatchDialogShow(SaltPayDialog.RegistrationError(value))
}
}
}
private suspend fun checkGasIfNeeded(
saltPayManager: SaltPayRegistrationManager,
step: SaltPayRegistrationStep,
@ -386,7 +321,7 @@ private suspend fun checkGasIfNeeded(
Timber.d("checkGasIfNeeded: for step: %s", step)
if (step == SaltPayRegistrationStep.KycStart ||
step == SaltPayRegistrationStep.KycWaiting ||
step == SaltPayRegistrationStep.ClaimSuccess
step == SaltPayRegistrationStep.Finished
) {
Timber.d("checkGasIfNeeded: no need to check for step: %s", step)
return Result.Success(Unit)
@ -451,6 +386,15 @@ fun RegistrationResponse.Item.toSaltPayStep(): SaltPayRegistrationStep {
// pinSet is false, go toPin screen
pinSet == false -> SaltPayRegistrationStep.NeedPin
kycStatus != null -> {
when (kycStatus) {
KYCStatus.NOT_STARTED, KYCStatus.STARTED -> SaltPayRegistrationStep.KycStart
KYCStatus.WAITING_FOR_APPROVAL -> SaltPayRegistrationStep.KycWaiting
KYCStatus.CORRECTION_REQUESTED, KYCStatus.REJECTED -> SaltPayRegistrationStep.KycReject
KYCStatus.APPROVED -> SaltPayRegistrationStep.Claim
null -> throw UnsupportedOperationException()
}
}
// kycDate is set, go to kyc waiting screen
kycDate != null -> SaltPayRegistrationStep.KycWaiting

View file

@ -123,7 +123,8 @@ enum class SaltPayRegistrationStep {
KycIntro,
KycStart,
KycWaiting,
KycReject,
Claim,
ClaimInProgress,
ClaimSuccess;
Finished;
}

View file

@ -20,6 +20,7 @@ import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.getDrawableCompat
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.setDrawable
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.extensions.stop
import com.tangem.tap.common.extensions.toFormattedCurrencyString
@ -58,12 +59,15 @@ internal class OnboardingSaltPayView(
private val toolbar: MaterialToolbar by lazy { walletFragment.binding.toolbar }
private val claimBinding: LayoutOnboardingMainBinding by lazy { walletFragment.bindingSaltPay.claim }
private val topContainer: LayoutOnboardingContainerTopBinding by lazy { claimBinding.onboardingTopContainer }
private val actionContainer: LayoutOnboardingContainerBottomBinding by lazy { claimBinding.onboardingActionContainer }
private val btnRefreshBalanceWidget by lazy {
RefreshBalanceWidget(claimBinding.onboardingTopContainer.onboardingWalletContainer)
}
private var progressButton: SaltPayProgressButton? = null
private var previousStep: SaltPayRegistrationStep = SaltPayRegistrationStep.None
fun newState(state: OnboardingWalletState) {
handleCardArtworks(state)
@ -135,9 +139,10 @@ internal class OnboardingSaltPayView(
SaltPayRegistrationStep.KycIntro -> handleKycIntro()
SaltPayRegistrationStep.KycStart -> handleKycStart(state)
SaltPayRegistrationStep.KycWaiting -> handleKycWaiting()
SaltPayRegistrationStep.KycReject -> handleKycReject()
SaltPayRegistrationStep.Claim -> handleClaim(state)
SaltPayRegistrationStep.ClaimInProgress -> handleClaim(state)
SaltPayRegistrationStep.ClaimSuccess -> handleClaim(state)
SaltPayRegistrationStep.Finished -> handleClaim(state)
}
progressButton?.changeState(state.mainButtonState)
}
@ -204,22 +209,41 @@ internal class OnboardingSaltPayView(
}
}
private fun handleKycWaiting() = with(walletFragment.bindingSaltPay) {
toolbar.title = getString(R.string.onboarding_navbar_kyc_waiting)
showOnlyView(verifyIdentityInProgress.root) {
progressButton = SaltPayProgressButton(verifyIdentityInProgress.root)
verifyIdentityInProgress.btnOpenSupportChat.setOnClickListener {
store.dispatch(GlobalAction.OpenChat(SupportInfo()))
}
verifyIdentityInProgress.btnRefresh.setOnClickListener {
store.dispatch(OnboardingSaltPayAction.Update)
}
private fun handleKycWaiting() = with(walletFragment.bindingSaltPay.kycInProgress) {
toolbar.title = getString(R.string.onboarding_navbar_kyc_progress)
showOnlyView(root)
imvInProgress.setDrawable(R.drawable.ic_in_progress)
tvHeader.text = getString(R.string.onboarding_title_kyc_waiting)
tvBody.text = getString(R.string.onboarding_subtitle_kyc_waiting)
btnOpenSupportChat.hide()
btnOpenSupportChat.setOnClickListener {
store.dispatch(GlobalAction.OpenChat(SupportInfo()))
}
btnKycAction.text = getString(R.string.onboarding_button_kyc_waiting)
btnKycAction.setOnClickListener {
store.dispatch(OnboardingSaltPayAction.Update)
}
progressButton = SaltPayProgressButton(root)
}
private val topContainer: LayoutOnboardingContainerTopBinding by lazy { claimBinding.onboardingTopContainer }
private val actionContainer: LayoutOnboardingContainerBottomBinding by lazy { claimBinding.onboardingActionContainer }
private var previousStep: SaltPayRegistrationStep = SaltPayRegistrationStep.None
private fun handleKycReject() = with(walletFragment.bindingSaltPay.kycInProgress) {
toolbar.title = getString(R.string.onboarding_navbar_kyc_progress)
showOnlyView(root)
imvInProgress.setDrawable(R.drawable.ic_reject)
tvHeader.text = getString(R.string.onboarding_title_kyc_retry)
tvBody.text = getString(R.string.onboarding_subtitle_kyc_retry)
btnOpenSupportChat.hide()
btnKycAction.text = getString(R.string.onboarding_button_kyc_start)
btnKycAction.setOnClickListener {
store.dispatch(OnboardingSaltPayAction.Update)
}
progressButton = SaltPayProgressButton(root)
}
private fun handleClaim(state: OnboardingSaltPayState) = with(walletFragment.bindingSaltPay) {
toolbar.title = getString(R.string.onboarding_navbar_claim)
@ -270,7 +294,7 @@ internal class OnboardingSaltPayView(
tvBody.text = getString(R.string.onboarding_subtitle_claim_progress)
btnMain.text = getString(R.string.onboarding_button_claim)
}
SaltPayRegistrationStep.ClaimSuccess -> {
SaltPayRegistrationStep.Finished -> {
tvHeader.setText(R.string.common_success)
tvBody.setText(R.string.onboarding_subtitle_success_claim)
@ -350,4 +374,4 @@ internal class OnboardingSaltPayView(
}
}
}
}
}

View file

@ -36,6 +36,23 @@ class SimpleOkDialog {
}
}.create()
}
}
fun create(dialog: AppDialog.SimpleOkErrorDialog, context: Context): AlertDialog = create(
dialog = AppDialog.SimpleOkDialog(
header = context.getString(R.string.common_error),
message = dialog.message,
onOk = dialog.onOk,
),
context = context,
)
fun create(dialog: AppDialog.SimpleOkWarningDialog, context: Context): AlertDialog = create(
dialog = AppDialog.SimpleOkDialog(
header = context.getString(R.string.common_warning),
message = dialog.message,
onOk = dialog.onOk,
),
context = context,
)
}
}

View file

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="142dp"
android:height="142dp"
android:viewportWidth="142"
android:viewportHeight="142">
<path
android:pathData="M71,0L71,0A71,71 0,0 1,142 71L142,71A71,71 0,0 1,71 142L71,142A71,71 0,0 1,0 71L0,71A71,71 0,0 1,71 0z"
android:fillColor="#ffffff"/>
<path
android:pathData="M71,142C110.21,142 142,110.21 142,71C142,31.79 110.21,0 71,0C31.79,0 0,31.79 0,71C0,110.21 31.79,142 71,142Z"
android:strokeAlpha="0.2"
android:fillColor="#DE1010"
android:fillType="evenOdd"
android:fillAlpha="0.2"/>
<path
android:pathData="M70.66,117.31C96.43,117.31 117.31,96.43 117.31,70.66C117.31,44.89 96.43,24 70.66,24C44.89,24 24,44.89 24,70.66C24,96.43 44.89,117.31 70.66,117.31Z"
android:fillColor="#DE1010"
android:fillType="evenOdd"/>
<path
android:pathData="M57.22,85.36H84.34C85.38,85.36 86.29,85.13 87.05,84.66C87.82,84.2 88.42,83.58 88.84,82.79C89.26,82.02 89.47,81.16 89.47,80.23C89.47,79.79 89.42,79.36 89.3,78.93C89.18,78.48 89.01,78.05 88.77,77.64L75.18,53.95C74.69,53.09 74.05,52.45 73.27,52.01C72.48,51.58 71.66,51.36 70.79,51.36C69.91,51.36 69.07,51.58 68.28,52.01C67.49,52.45 66.86,53.09 66.38,53.95L52.79,77.64C52.32,78.46 52.09,79.32 52.09,80.23C52.09,81.16 52.3,82.02 52.72,82.79C53.14,83.58 53.73,84.2 54.49,84.66C55.27,85.13 56.18,85.36 57.22,85.36ZM57.73,81.63C57.24,81.63 56.84,81.46 56.55,81.12C56.26,80.78 56.11,80.39 56.11,79.95C56.11,79.8 56.12,79.65 56.15,79.49C56.18,79.32 56.24,79.17 56.32,79.01L69.38,56.14C69.54,55.88 69.74,55.68 70,55.56C70.26,55.45 70.52,55.39 70.79,55.39C71.06,55.39 71.32,55.45 71.56,55.56C71.82,55.68 72.02,55.88 72.16,56.14L85.24,79.05C85.39,79.34 85.47,79.64 85.47,79.95C85.47,80.39 85.31,80.78 85.01,81.12C84.72,81.46 84.32,81.63 83.81,81.63H57.73ZM70.81,72.95C71.87,72.95 72.43,72.39 72.48,71.28L72.74,63.3C72.76,62.74 72.59,62.28 72.21,61.93C71.85,61.56 71.38,61.38 70.79,61.38C70.19,61.38 69.71,61.56 69.35,61.93C68.98,62.28 68.81,62.73 68.84,63.28L69.08,71.3C69.13,72.4 69.71,72.95 70.81,72.95ZM70.81,78.86C71.4,78.86 71.91,78.67 72.34,78.31C72.76,77.94 72.97,77.46 72.97,76.87C72.97,76.27 72.76,75.79 72.34,75.41C71.93,75.04 71.42,74.85 70.81,74.85C70.2,74.85 69.68,75.04 69.24,75.43C68.82,75.8 68.61,76.28 68.61,76.87C68.61,77.44 68.82,77.92 69.24,78.29C69.68,78.67 70.2,78.86 70.81,78.86Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -9,12 +9,19 @@
android:id="@+id/imv_in_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="113dp"
android:layout_marginTop="100dp"
android:src="@drawable/ic_in_progress"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="@dimen/onboarding_wallet_top_guide_line_weight" />
<TextView
android:id="@+id/tv_header"
style="@style/TextViewOnboarding.Header"
@ -24,8 +31,7 @@
app:layout_constraintBottom_toTopOf="@+id/tv_body"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imv_in_progress"
app:layout_constraintVertical_chainStyle="packed" />
app:layout_constraintTop_toBottomOf="@+id/guideline1" />
<TextView
android:id="@+id/tv_body"
@ -36,7 +42,6 @@
android:layout_marginTop="14dp"
android:layout_marginEnd="55dp"
android:text="@string/onboarding_subtitle_kyc_waiting"
app:layout_constraintBottom_toTopOf="@+id/btn_open_support_chat"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_header" />
@ -62,7 +67,7 @@
app:layout_constraintStart_toStartOf="parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_refresh"
android:id="@+id/btn_kyc_action"
style="@style/OnboardingButton"
android:layout_height="wrap_content"
android:text="@string/onboarding_button_kyc_waiting" />

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -11,15 +11,29 @@
android:id="@+id/onboarding_top_container"
layout="@layout/layout_onboarding_container_top"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_height="wrap_content"
android:layout_weight="@dimen/home_top_weight"
android:clipChildren="false" />
android:clipChildren="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintGuide_percent="@dimen/onboarding_wallet_top_guide_line_weight"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/onboarding_action_container"
layout="@layout/layout_onboarding_container_bottom"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="@dimen/home_bottom_weight" />
android:layout_height="wrap_content"
android:layout_weight="@dimen/home_bottom_weight"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline3" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -16,7 +16,7 @@
<include
android:id="@+id/verify_identity"
layout="@layout/layout_onboarding_saltpay_verify_identity"
layout="@layout/layout_onboarding_saltpay_kyc_start"
android:visibility="gone" />
<WebView
@ -28,13 +28,13 @@
android:visibility="gone" />
<include
android:id="@+id/verify_identity_in_progress"
layout="@layout/layout_onboarding_saltpay_verify_identity_in_progress"
android:id="@+id/kyc_in_progress"
layout="@layout/layout_onboarding_saltpay_kyc_in_progress"
android:visibility="gone" />
<include
android:id="@+id/claim"
layout="@layout/layout_onboarding_main"
android:visibility="gone"/>
android:visibility="gone" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/imv_in_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:src="@drawable/ic_in_progress"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.4" />
<TextView
android:id="@+id/tv_header"
style="@style/TextViewOnboarding.Header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/onboarding_title_kyc_waiting"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline1" />
<TextView
android:id="@+id/tv_body"
style="@style/TextViewOnboarding.Body"
android:layout_width="302dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="14dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_header"
tools:text="@string/onboarding_subtitle_kyc_waiting" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_open_support_chat"
style="@style/OnboardingButton.Alternative"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="92dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/btn_container"
app:layout_constraintStart_toStartOf="@id/btn_container"
tools:text="@string/onboarding_supplement_button_kyc_waiting" />
<FrameLayout
android:id="@+id/btn_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_kyc_action"
style="@style/OnboardingButton"
android:layout_height="wrap_content"
android:text="@string/onboarding_button_kyc_waiting" />
<ProgressBar
android:id="@+id/progress"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="center"
android:elevation="18dp"
android:indeterminate="true"
android:indeterminateTint="@color/backgroundLightGray"
android:visibility="gone" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -149,4 +149,8 @@
<string name="onboarding_subtitle_success_claim">Congratulations! Your first payment crypto card has been activated</string>
<string name="onboarding_title_claim_progress">Claiming</string>
<string name="onboarding_subtitle_claim_progress">It will take a few seconds</string>
<string name="onboarding_title_kyc_retry">Something went wrong</string>
<string name="onboarding_subtitle_kyc_retry">Please check you email for further instructions</string>
<string name="onboarding_exit_alert_title">Do you want to exit the activation process?</string>
<string name="onboarding_exit_alert_message">In this case, you will need to start from the beginning.</string>
</resources>

View file

@ -149,4 +149,8 @@
<string name="onboarding_subtitle_success_claim">Congratulations! Your first payment crypto card has been activated</string>
<string name="onboarding_title_claim_progress">Claiming</string>
<string name="onboarding_subtitle_claim_progress">It will take a few seconds</string>
<string name="onboarding_title_kyc_retry">Something went wrong</string>
<string name="onboarding_subtitle_kyc_retry">Please check you email for further instructions</string>
<string name="onboarding_exit_alert_title">Do you want to exit the activation process?</string>
<string name="onboarding_exit_alert_message">In this case, you will need to start from the beginning.</string>
</resources>

View file

@ -149,4 +149,8 @@
<string name="onboarding_subtitle_success_claim">Congratulations! Your first payment crypto card has been activated</string>
<string name="onboarding_title_claim_progress">Claiming</string>
<string name="onboarding_subtitle_claim_progress">It will take a few seconds</string>
<string name="onboarding_title_kyc_retry">Something went wrong</string>
<string name="onboarding_subtitle_kyc_retry">Please check you email for further instructions</string>
<string name="onboarding_exit_alert_title">Do you want to exit the activation process?</string>
<string name="onboarding_exit_alert_message">In this case, you will need to start from the beginning.</string>
</resources>

View file

@ -142,9 +142,13 @@
<string name="onboarding_chat_button_title">Чат</string>
<string name="onboarding_navbar_claim">Начало работы</string>
<string name="onboarding_title_claim">Запросить %s</string>
<string name="onboarding_subtitle_claim">Для начала работы просто запросите начисление xDai на свой кошелек</string>
<string name="onboarding_subtitle_claim">Для начала работы просто запросите начисление wxDai на свой кошелек</string>
<string name="onboarding_button_claim">Запросить</string>
<string name="onboarding_subtitle_success_claim">Поздравляем! Ваша платежная крипто карта теперь активирована!</string>
<string name="onboarding_title_claim_progress">Запрашивается</string>
<string name="onboarding_subtitle_claim_progress">Это займет несколько секунд</string>
<string name="onboarding_title_kyc_retry">Что-то пошло не так</string>
<string name="onboarding_subtitle_kyc_retry">Более подробная информация отправлена на ваш адрес электронной почты.</string>
<string name="onboarding_exit_alert_title">Вы хотите выйти из процесса активации?</string>
<string name="onboarding_exit_alert_message">В этом случае вам будет необходимо начать процесс заново.</string>
</resources>

View file

@ -149,4 +149,8 @@
<string name="onboarding_subtitle_success_claim">Congratulations! Your first payment crypto card has been activated</string>
<string name="onboarding_title_claim_progress">Claiming</string>
<string name="onboarding_subtitle_claim_progress">It will take a few seconds</string>
<string name="onboarding_title_kyc_retry">Something went wrong</string>
<string name="onboarding_subtitle_kyc_retry">Please check you email for further instructions</string>
<string name="onboarding_exit_alert_title">Do you want to exit the activation process?</string>
<string name="onboarding_exit_alert_message">In this case, you will need to start from the beginning.</string>
</resources>

View file

@ -28,12 +28,23 @@ data class RegistrationResponse(
val kycProvider: String?,
@Json(name = "kyc_date")
val kycDate: String?,
@Json(name = "kyc_status")
val kycStatus: KYCStatus?,
@Json(name = "disabled_by_admin")
val disabledByAdmin: Boolean?,
val error: String?,
)
}
enum class KYCStatus {
NOT_STARTED,
STARTED,
WAITING_FOR_APPROVAL,
CORRECTION_REQUESTED,
REJECTED,
APPROVED,
}
data class AttestationResponse(
val challenge: ByteArray?,
val success: Boolean,