Updated on 2026-08-14
This commit is contained in:
parent
5ec2a0c5d5
commit
a74efa2951
5 changed files with 491 additions and 157 deletions
|
|
@ -30,5 +30,16 @@ class OnboardingSaltPayHelper {
|
|||
Result.Failure(error)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testProceedToOnboarding(scanResponse: ScanResponse): Result<Boolean> {
|
||||
return try {
|
||||
val isBackupOnboardingCase = scanResponse.card.backupStatus?.isActive == false
|
||||
Result.Success(isBackupOnboardingCase)
|
||||
} catch (ex: Exception) {
|
||||
Result.Failure(ex)
|
||||
} catch (error: SaltPayRegistrationError){
|
||||
Result.Failure(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui
|
||||
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupState
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.FIRST_BACKUP
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.ORIGIN
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.SECOND_BACKUP
|
||||
import com.tangem.wallet.databinding.FragmentOnboardingWalletBinding
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface BackupAnimator {
|
||||
fun updateBackupState(backupState: BackupState)
|
||||
fun setupCreateWalletState()
|
||||
fun showBackupIntro(state: BackupState)
|
||||
fun showScanOriginCard()
|
||||
fun showAddBackupCards(state: BackupState, backupCardsCounts: Int)
|
||||
fun showWritePrimaryCard(state: BackupState)
|
||||
fun showWriteBackupCard(state: BackupState, backupCard: Int)
|
||||
fun showSuccess(onEnd: () -> Unit)
|
||||
}
|
||||
|
||||
class WalletBackupAnimator(
|
||||
private val cardsWidget: WalletCardsWidget,
|
||||
) : BackupAnimator {
|
||||
|
||||
private val viewState: State = when (cardsWidget.leapfrogWidget.getViewsCount()) {
|
||||
2 -> State.TwoCards
|
||||
3 -> State.TreeCards
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
private var currentStep = 0
|
||||
|
||||
override fun updateBackupState(backupState: BackupState) {
|
||||
}
|
||||
|
||||
override fun setupCreateWalletState() {
|
||||
currentStep = STEP_CREATE_WALLET
|
||||
|
||||
cardsWidget.toFolded(false)
|
||||
|
||||
ORIGIN.alpha(1f)
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
SECOND_BACKUP.alpha(1f)
|
||||
}
|
||||
|
||||
override fun showBackupIntro(state: BackupState) {
|
||||
currentStep = STEP_BACKUP_INTRO
|
||||
|
||||
ORIGIN.show()
|
||||
FIRST_BACKUP.show()
|
||||
SECOND_BACKUP.show()
|
||||
|
||||
cardsWidget.toWelcome()
|
||||
}
|
||||
|
||||
override fun showScanOriginCard() {
|
||||
currentStep = STEP_SCAN_ORIGIN_CARD
|
||||
|
||||
cardsWidget.toFolded()
|
||||
}
|
||||
|
||||
override fun showAddBackupCards(state: BackupState, backupCardsCounts: Int) {
|
||||
when (backupCardsCounts) {
|
||||
0 -> {
|
||||
when (currentStep) {
|
||||
STEP_CREATE_WALLET -> {
|
||||
cardsWidget.toFolded(false) { cardsWidget.toFan() }
|
||||
|
||||
FIRST_BACKUP.animateAlpha(0.6f, 0)
|
||||
SECOND_BACKUP.animateAlpha(0.2f, 400)
|
||||
}
|
||||
STEP_BACKUP_INTRO -> {
|
||||
cardsWidget.toFolded(duration = 200) { cardsWidget.toFan() }
|
||||
FIRST_BACKUP.animateAlpha(0.6f, 400, 250)
|
||||
SECOND_BACKUP.animateAlpha(0.2f, 400, 250)
|
||||
}
|
||||
STEP_SCAN_ORIGIN_CARD -> {
|
||||
cardsWidget.toFan()
|
||||
FIRST_BACKUP.animateAlpha(0.6f, 400, 250)
|
||||
SECOND_BACKUP.animateAlpha(0.2f, 400, 250)
|
||||
}
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
cardsWidget.toFan(false)
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
SECOND_BACKUP.alpha(0.2f)
|
||||
}
|
||||
2 -> {
|
||||
cardsWidget.toFan(false)
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
SECOND_BACKUP.alpha(1f)
|
||||
}
|
||||
}
|
||||
|
||||
currentStep = STEP_ADD_BACKUP_CARDS
|
||||
}
|
||||
|
||||
override fun showWritePrimaryCard(state: BackupState) {
|
||||
currentStep = STEP_WRITE_PRIMARY_CARD
|
||||
|
||||
cardsWidget.toLeapfrog(
|
||||
onEndFold = {
|
||||
FIRST_BACKUP.alpha(0.4f)
|
||||
SECOND_BACKUP.alpha(0.2f)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun showWriteBackupCard(state: BackupState, backupCard: Int) {
|
||||
currentStep = STEP_WRITE_BACKUP_CARD
|
||||
|
||||
when (viewState) {
|
||||
State.TwoCards -> {
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
cardsWidget.leapfrogWidget.leap {
|
||||
ORIGIN.alpha(0.4f)
|
||||
}
|
||||
}
|
||||
State.TreeCards -> {
|
||||
when (backupCard) {
|
||||
1 -> {
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
cardsWidget.leapfrogWidget.leap {
|
||||
SECOND_BACKUP.alpha(0.4f)
|
||||
ORIGIN.alpha(0.2f)
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
SECOND_BACKUP.alpha(1f)
|
||||
cardsWidget.leapfrogWidget.leap {
|
||||
ORIGIN.alpha(0.4f)
|
||||
FIRST_BACKUP.alpha(0.2f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun showSuccess(onEnd: () -> Unit) {
|
||||
currentStep = STEP_SUCCESS
|
||||
cardsWidget.leapfrogWidget.fold(onEnd = onEnd)
|
||||
}
|
||||
|
||||
private enum class State {
|
||||
TreeCards,
|
||||
TwoCards
|
||||
}
|
||||
|
||||
private fun BackupCardType.animateAlpha(
|
||||
alpha: Float,
|
||||
duration: Long = 0L,
|
||||
startDelay: Long = 0L,
|
||||
) {
|
||||
when (this) {
|
||||
ORIGIN -> {
|
||||
cardsWidget.getOriginCardView().animate().apply {
|
||||
alpha(alpha)
|
||||
this.startDelay = startDelay
|
||||
this.duration = duration
|
||||
}
|
||||
}
|
||||
FIRST_BACKUP -> {
|
||||
cardsWidget.getFirstBackupCardView().animate().apply {
|
||||
alpha(alpha)
|
||||
this.startDelay = startDelay
|
||||
this.duration = duration
|
||||
}
|
||||
}
|
||||
SECOND_BACKUP -> {
|
||||
if (viewState != State.TreeCards) return
|
||||
cardsWidget.getSecondBackupCardView().animate().apply {
|
||||
alpha(alpha)
|
||||
this.startDelay = startDelay
|
||||
this.duration = duration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun BackupCardType.alpha(alpha: Float) {
|
||||
when (this) {
|
||||
ORIGIN -> cardsWidget.getOriginCardView().alpha = alpha
|
||||
FIRST_BACKUP -> cardsWidget.getFirstBackupCardView().alpha = alpha
|
||||
SECOND_BACKUP -> {
|
||||
if (viewState != State.TreeCards) return
|
||||
cardsWidget.getSecondBackupCardView().alpha = alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun BackupCardType.show() {
|
||||
when (this) {
|
||||
ORIGIN -> cardsWidget.getOriginCardView().show()
|
||||
FIRST_BACKUP -> cardsWidget.getFirstBackupCardView().show()
|
||||
SECOND_BACKUP -> {
|
||||
if (viewState != State.TreeCards) return
|
||||
cardsWidget.getSecondBackupCardView().show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STEP_CREATE_WALLET = 0
|
||||
private const val STEP_BACKUP_INTRO = 1
|
||||
private const val STEP_SCAN_ORIGIN_CARD = 2
|
||||
private const val STEP_ADD_BACKUP_CARDS = 3
|
||||
private const val STEP_WRITE_PRIMARY_CARD = 4
|
||||
private const val STEP_WRITE_BACKUP_CARD = 5
|
||||
private const val STEP_SUCCESS = 6
|
||||
}
|
||||
}
|
||||
|
||||
class TestBackupAnimation(
|
||||
private val animator: BackupAnimator,
|
||||
binding: FragmentOnboardingWalletBinding,
|
||||
) : BackupAnimator {
|
||||
|
||||
private lateinit var state: BackupState
|
||||
private var steps = 0
|
||||
|
||||
init {
|
||||
init(binding, this)
|
||||
}
|
||||
|
||||
fun setStep(step: Int, onStepUpdate: (Int) -> Unit = {}) {
|
||||
steps = step
|
||||
when (steps) {
|
||||
0 -> setupCreateWalletState()
|
||||
1 -> showBackupIntro(state)
|
||||
2 -> showScanOriginCard()
|
||||
3 -> showAddBackupCards(state, 0)
|
||||
4 -> showAddBackupCards(state, 1)
|
||||
5 -> showAddBackupCards(state, 2)
|
||||
6 -> showWritePrimaryCard(state)
|
||||
7 -> showWriteBackupCard(state, 1)
|
||||
8 -> showWriteBackupCard(state, 2)
|
||||
else -> setStep(0)
|
||||
}
|
||||
onStepUpdate(steps)
|
||||
}
|
||||
|
||||
fun onNext(onStepUpdate: (Int) -> Unit) {
|
||||
steps++
|
||||
setStep(steps, onStepUpdate)
|
||||
}
|
||||
|
||||
override fun updateBackupState(backupState: BackupState) {
|
||||
this.state = backupState
|
||||
}
|
||||
|
||||
override fun setupCreateWalletState() {
|
||||
animator.setupCreateWalletState()
|
||||
}
|
||||
|
||||
override fun showBackupIntro(state: BackupState) {
|
||||
animator.showBackupIntro(state)
|
||||
}
|
||||
|
||||
override fun showScanOriginCard() {
|
||||
animator.showScanOriginCard()
|
||||
}
|
||||
|
||||
override fun showAddBackupCards(state: BackupState, backupCardsCounts: Int) {
|
||||
animator.showAddBackupCards(state, backupCardsCounts)
|
||||
}
|
||||
|
||||
override fun showWritePrimaryCard(state: BackupState) {
|
||||
animator.showWritePrimaryCard(state)
|
||||
}
|
||||
|
||||
override fun showWriteBackupCard(state: BackupState, backupCard: Int) {
|
||||
animator.showWriteBackupCard(state, backupCard)
|
||||
}
|
||||
|
||||
override fun showSuccess(onEnd: () -> Unit) {
|
||||
animator.showSuccess(onEnd)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun init(binding: FragmentOnboardingWalletBinding, animator: TestBackupAnimation) {
|
||||
val button = MaterialButton(binding.onboardingRoot.context).apply { text = "Next" }
|
||||
button.setOnClickListener { animator.onNext { button.text = "$it" } }
|
||||
binding.onboardingRoot.addView(button, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import android.util.TypedValue
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
|
@ -30,6 +31,7 @@ import com.tangem.tap.common.extensions.configureSettings
|
|||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.inflate
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.stop
|
||||
import com.tangem.tap.common.feedback.SupportInfo
|
||||
|
|
@ -63,7 +65,7 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
StoreSubscriber<OnboardingWalletState>, FragmentOnBackPressedHandler {
|
||||
|
||||
private val pbBinding: ViewOnboardingProgressBinding by viewBinding(ViewOnboardingProgressBinding::bind)
|
||||
private val binding: FragmentOnboardingWalletBinding by viewBinding(FragmentOnboardingWalletBinding::bind)
|
||||
val binding: FragmentOnboardingWalletBinding by viewBinding(FragmentOnboardingWalletBinding::bind)
|
||||
private val bindingSaltPay: LayoutOnboardingSaltpayBinding by lazy { binding.onboardingSaltpayContainer }
|
||||
|
||||
private val saltPayView: SaltPayView = SaltPayView(this)
|
||||
|
|
@ -71,9 +73,10 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
private lateinit var cardsWidget: WalletCardsWidget
|
||||
private var accessCodeDialog: AccessCodeDialog? = null
|
||||
|
||||
private lateinit var animator: BackupAnimator
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
postponeEnterTransition()
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
|
|
@ -84,16 +87,8 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val typedValue = TypedValue()
|
||||
resources.getValue(R.dimen.device_scale_factor_for_twins_welcome, typedValue, true)
|
||||
val deviceScaleFactor = typedValue.float
|
||||
|
||||
val leapfrogCalculator = PropertyCalculator(
|
||||
yTranslationFactor = 25f * deviceScaleFactor,
|
||||
)
|
||||
val leapfrog = LeapfrogWidget(binding.flCardsContainer, leapfrogCalculator)
|
||||
cardsWidget = WalletCardsWidget(leapfrog, deviceScaleFactor) { 200f * deviceScaleFactor }
|
||||
startPostponedEnterTransition()
|
||||
val scaleFactor = getDeviceScaleFactor()
|
||||
initCardsWidget(createLeapfrogWidget(binding.flCardsContainer, scaleFactor), scaleFactor)
|
||||
|
||||
binding.viewPagerBackupInfo.adapter = BackupInfoAdapter()
|
||||
TabLayoutMediator(
|
||||
|
|
@ -113,6 +108,37 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
store.dispatch(OnboardingWalletAction.LoadArtwork)
|
||||
}
|
||||
|
||||
private fun reInitCardsWidget(backupCardsCounts: Int) = with(binding) {
|
||||
val viewBackupCount = flCardsContainer.childCount - 1
|
||||
if (viewBackupCount <= 0) return@with
|
||||
if (viewBackupCount == backupCardsCounts) return@with
|
||||
|
||||
cardsWidget.toFolded(false)
|
||||
|
||||
if (viewBackupCount > backupCardsCounts) {
|
||||
flCardsContainer.removeViewAt(viewBackupCount - 1)
|
||||
} else {
|
||||
flCardsContainer.inflate(R.layout.view_onboarding_card, true)
|
||||
}
|
||||
|
||||
val scaleFactor = getDeviceScaleFactor()
|
||||
initCardsWidget(createLeapfrogWidget(flCardsContainer, scaleFactor), scaleFactor)
|
||||
}
|
||||
|
||||
private fun createLeapfrogWidget(container: FrameLayout, deviceScaleFactor: Float): LeapfrogWidget {
|
||||
val leapfrogCalculator = PropertyCalculator(yTranslationFactor = 25f * deviceScaleFactor)
|
||||
return LeapfrogWidget(container, leapfrogCalculator)
|
||||
}
|
||||
|
||||
private fun initCardsWidget(leapfrogWidget: LeapfrogWidget, deviceScaleFactor: Float, isTest: Boolean = false) {
|
||||
cardsWidget = WalletCardsWidget(leapfrogWidget, deviceScaleFactor) { 200f * deviceScaleFactor }
|
||||
animator = if (isTest) {
|
||||
TestBackupAnimation(WalletBackupAnimator(cardsWidget), binding)
|
||||
} else {
|
||||
WalletBackupAnimator(cardsWidget)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
|
|
@ -129,7 +155,9 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
|
||||
override fun newState(state: OnboardingWalletState) {
|
||||
if (activity == null || view == null) return
|
||||
if (state.isSaltPay) reInitCardsWidget(1)
|
||||
|
||||
animator.updateBackupState(state.backupState)
|
||||
requireActivity().invalidateOptionsMenu()
|
||||
|
||||
pbBinding.pbState.max = state.getMaxProgress()
|
||||
|
|
@ -171,7 +199,7 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
tvHeader.setText(R.string.onboarding_create_wallet_header)
|
||||
tvBody.setText(R.string.onboarding_create_wallet_body)
|
||||
|
||||
cardsWidget.toFolded(false) { startPostponedEnterTransition() }
|
||||
animator.setupCreateWalletState()
|
||||
}
|
||||
|
||||
private fun setBackupState(state: BackupState, isSaltPay: Boolean) {
|
||||
|
|
@ -192,8 +220,6 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
|
||||
cardsWidget.toWelcome()
|
||||
|
||||
tvHeader.hide()
|
||||
tvBody.hide()
|
||||
viewPagerBackupInfo.show()
|
||||
|
|
@ -207,15 +233,11 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
btnAlternativeAction.setOnClickListener { store.dispatch(BackupAction.DismissBackup) }
|
||||
btnAlternativeAction.show(state.canSkipBackup && !isSaltPay)
|
||||
}
|
||||
|
||||
startPostponedEnterTransition()
|
||||
animator.showBackupIntro(state)
|
||||
}
|
||||
|
||||
private fun showScanOriginCard() = with(binding) {
|
||||
prepareBackupView()
|
||||
|
||||
cardsWidget.toFolded()
|
||||
|
||||
tvHeader.text = getText(R.string.onboarding_title_scan_origin_card)
|
||||
tvBody.text = getString(
|
||||
R.string.onboarding_subtitle_scan_origin_card,
|
||||
|
|
@ -226,18 +248,8 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
btnAlternativeAction.hide()
|
||||
btnMainAction.setOnClickListener { store.dispatch(BackupAction.ScanPrimaryCard) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareBackupView() = with(binding) {
|
||||
toolbar.title = getText(R.string.onboarding_navbar_title_creating_backup)
|
||||
|
||||
tvHeader.show()
|
||||
tvBody.show()
|
||||
viewPagerBackupInfo.hide()
|
||||
tabLayoutBackupInfo.hide()
|
||||
|
||||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
animator.showScanOriginCard()
|
||||
}
|
||||
|
||||
private fun showAddBackupCards(state: BackupState, isSaltPay: Boolean) = with(binding) {
|
||||
|
|
@ -261,35 +273,37 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
|
||||
if (isSaltPay) {
|
||||
saltPayView.showAddBackupCards(state)
|
||||
return@with
|
||||
}
|
||||
|
||||
when (state.backupCardsNumber) {
|
||||
0 -> {
|
||||
cardsWidget.toFan {
|
||||
cardsWidget.getFirstBackupCardView().animate().alpha(0.6f).duration = 200
|
||||
cardsWidget.getSecondBackupCardView().animate().alpha(0.2f).duration = 200
|
||||
} else {
|
||||
when (state.backupCardsNumber) {
|
||||
0 -> {
|
||||
tvHeader.text = getText(R.string.onboarding_title_no_backup_cards)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_no_backup_cards)
|
||||
}
|
||||
tvHeader.text = getText(R.string.onboarding_title_no_backup_cards)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_no_backup_cards)
|
||||
}
|
||||
1 -> {
|
||||
tvHeader.text = getText(R.string.onboarding_title_one_backup_card)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_one_backup_card)
|
||||
|
||||
cardsWidget.toFan(false)
|
||||
cardsWidget.getFirstBackupCardView().animate().alpha(1f).duration = 400
|
||||
cardsWidget.getSecondBackupCardView().alpha = 0.2f
|
||||
}
|
||||
2 -> {
|
||||
tvHeader.text = getText(R.string.onboarding_title_two_backup_cards)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_two_backup_cards)
|
||||
|
||||
cardsWidget.toFan(false)
|
||||
cardsWidget.getFirstBackupCardView().alpha = 1f
|
||||
cardsWidget.getSecondBackupCardView().animate().alpha(1f).duration = 400
|
||||
1 -> {
|
||||
tvHeader.text = getText(R.string.onboarding_title_one_backup_card)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_one_backup_card)
|
||||
}
|
||||
2 -> {
|
||||
tvHeader.text = getText(R.string.onboarding_title_two_backup_cards)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_two_backup_cards)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
animator.showAddBackupCards(state, state.backupCardsNumber)
|
||||
}
|
||||
|
||||
private fun prepareBackupView() = with(binding) {
|
||||
toolbar.title = getText(R.string.onboarding_navbar_title_creating_backup)
|
||||
|
||||
tvHeader.show()
|
||||
tvBody.show()
|
||||
viewPagerBackupInfo.hide()
|
||||
tabLayoutBackupInfo.hide()
|
||||
|
||||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
}
|
||||
|
||||
private fun showSetAccessCode() {
|
||||
|
|
@ -323,13 +337,8 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
private fun showWritePrimaryCard(state: BackupState, isSaltPay: Boolean) = with(binding) {
|
||||
accessCodeDialog?.dismiss()
|
||||
|
||||
reInitCardsWidget(state.backupCardsNumber)
|
||||
prepareViewForFinalizeStep()
|
||||
cardsWidget.getSecondBackupCardView().show(state.backupCardsNumber == 2)
|
||||
|
||||
cardsWidget.toLeapfrog {
|
||||
cardsWidget.getFirstBackupCardView().alpha = 0.6f
|
||||
cardsWidget.getSecondBackupCardView().alpha = 0.2f
|
||||
}
|
||||
|
||||
val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4))
|
||||
if (isSaltPay) {
|
||||
|
|
@ -344,52 +353,33 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
)
|
||||
layoutButtonsCommon.btnMainAction.text = getText(R.string.onboarding_button_backup_origin)
|
||||
}
|
||||
|
||||
layoutButtonsCommon.btnMainAction.setOnClickListener { store.dispatch(BackupAction.WritePrimaryCard) }
|
||||
|
||||
animator.showWritePrimaryCard(state)
|
||||
}
|
||||
|
||||
private fun prepareViewForFinalizeStep() = with(binding) {
|
||||
layoutButtonsAddCards.root.hide()
|
||||
layoutButtonsCommon.root.show()
|
||||
|
||||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
|
||||
toolbar.title = getText(R.string.onboarding_button_finalize_backup)
|
||||
|
||||
imvCardBackground.hide()
|
||||
|
||||
cardsWidget.toLeapfrog()
|
||||
|
||||
layoutButtonsAddCards.root.hide()
|
||||
layoutButtonsCommon.root.show()
|
||||
layoutButtonsCommon.btnAlternativeAction.hide()
|
||||
|
||||
imvCardBackground.hide()
|
||||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
}
|
||||
|
||||
private fun showWriteBackupCard(state: BackupState, isSaltPay: Boolean) = with(binding) {
|
||||
prepareViewForFinalizeStep()
|
||||
|
||||
cardsWidget.getSecondBackupCardView().show(state.backupCardsNumber == 2)
|
||||
|
||||
val cardNumber = (state.backupStep as? BackupStep.WriteBackupCard)?.cardNumber ?: 1
|
||||
when (cardNumber) {
|
||||
1 -> cardsWidget.leapfrogWidget.leap {
|
||||
cardsWidget.getOriginCardView().alpha = 0.4f
|
||||
cardsWidget.getFirstBackupCardView().alpha = 0.2f
|
||||
cardsWidget.getSecondBackupCardView().alpha = 1f
|
||||
}
|
||||
2 -> cardsWidget.leapfrogWidget.leap {
|
||||
cardsWidget.getOriginCardView().alpha = 0.4f
|
||||
cardsWidget.getFirstBackupCardView().alpha = 0.2f
|
||||
cardsWidget.getSecondBackupCardView().alpha = 1f
|
||||
}
|
||||
}
|
||||
|
||||
val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4))
|
||||
if (isSaltPay) {
|
||||
tvHeader.text = getString(R.string.onboarding_saltpay_title_backup_card)
|
||||
tvBody.text = getString(R.string.onboarding_twins_interrupt_warning)
|
||||
layoutButtonsCommon.btnMainAction.text = getString(R.string.onboarding_saltpay_title_backup_card)
|
||||
} else {
|
||||
val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4))
|
||||
tvHeader.text = getString(R.string.onboarding_title_backup_card_format, cardNumber)
|
||||
tvBody.text = getString(
|
||||
R.string.onboarding_subtitle_scan_backup_card_format,
|
||||
|
|
@ -403,6 +393,8 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
layoutButtonsCommon.btnMainAction.setOnClickListener {
|
||||
store.dispatch(BackupAction.WriteBackupCard(cardNumber))
|
||||
}
|
||||
|
||||
animator.showWriteBackupCard(state, cardNumber)
|
||||
}
|
||||
|
||||
private fun showSuccess() = with(binding) {
|
||||
|
|
@ -423,16 +415,14 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
store.dispatch(OnboardingWalletAction.FinishOnboarding)
|
||||
}
|
||||
|
||||
cardsWidget.leapfrogWidget.fold {
|
||||
animator.showSuccess {
|
||||
flCardsContainer.hide()
|
||||
imvCardBackground.hide()
|
||||
vConfetti.lavConfetti.show()
|
||||
vConfetti.lavConfetti.playAnimation()
|
||||
imvSuccess.alpha = 0f
|
||||
imvSuccess.show()
|
||||
|
||||
imvSuccess.animate()
|
||||
?.alpha(1f)?.duration = 400
|
||||
imvSuccess.animate()?.alpha(1f)?.duration = 400
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -450,6 +440,7 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
|
||||
fun newState(state: OnboardingWalletState) {
|
||||
handleCardArtworks(state)
|
||||
|
||||
when (state.step) {
|
||||
OnboardingWalletStep.SaltPay -> setSaltPayStep(state.onboardingSaltPayState)
|
||||
OnboardingWalletStep.Backup -> {
|
||||
|
|
@ -489,24 +480,20 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
//TODO: at now we can hide the image only by changing alpha channel to 0, because
|
||||
// the OnboardingWalletFragment and WalletCardsWidget manipulate it visibility through changing
|
||||
// View.VISIBILITY states.
|
||||
imvSecondBackupCard.alpha = 0f
|
||||
// imvSecondBackupCard.alpha = 0f
|
||||
}
|
||||
|
||||
fun showAddBackupCards(state: BackupState) = with(walletFragment.binding) {
|
||||
walletFragment.cardsWidget.getSecondBackupCardView().alpha = 0f
|
||||
when (state.backupCardsNumber) {
|
||||
0 -> {
|
||||
tvHeader.text = walletFragment.getText(R.string.onboarding_saltpay_title_no_backup_card)
|
||||
tvBody.text = walletFragment.getText(R.string.onboarding_saltpay_subtitle_no_backup_cards)
|
||||
walletFragment.cardsWidget.getFirstBackupCardView().alpha = 0.6f
|
||||
walletFragment.cardsWidget.toFan()
|
||||
}
|
||||
1 -> {
|
||||
tvHeader.text = walletFragment.getText(R.string.onboarding_saltpay_title_one_backup_card)
|
||||
tvBody.text = walletFragment.getText(R.string.onboarding_saltpay_subtitle_one_backup_card)
|
||||
walletFragment.cardsWidget.toFan(false)
|
||||
walletFragment.cardsWidget.getFirstBackupCardView().animate().alpha(1f).duration = 400
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -614,7 +601,6 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
}
|
||||
|
||||
private fun showOnlyView(view: View, onShowListener: (() -> Unit)? = null) {
|
||||
// onboardingSaltpayContainer.beginDelayedTransition()
|
||||
walletFragment.bindingSaltPay.onboardingSaltpayContainer.children
|
||||
.filter { it.id != view.id }
|
||||
.forEach { it.hide() }
|
||||
|
|
@ -639,4 +625,10 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDeviceScaleFactor(): Float {
|
||||
val typedValue = TypedValue()
|
||||
resources.getValue(R.dimen.device_scale_factor_for_twins_welcome, typedValue, true)
|
||||
return typedValue.float
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,87 +16,100 @@ class WalletCardsWidget(
|
|||
val getTopOfAnchorViewForActivateState: () -> Float,
|
||||
) {
|
||||
|
||||
val animDuration: Long = 400
|
||||
private val animDuration: Long = 400
|
||||
|
||||
var currentState: WidgetState? = null
|
||||
private set
|
||||
|
||||
fun toWelcome(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
fun toWelcome(
|
||||
animate: Boolean = true,
|
||||
onEnd: () -> Unit = {},
|
||||
) {
|
||||
if (currentState == WidgetState.WELCOME) return
|
||||
|
||||
currentState = WidgetState.WELCOME
|
||||
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createWelcomeProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createWelcomeProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createWelcomeProperties(BackupCardType.SECOND_BACKUP)),
|
||||
)
|
||||
val animator = createAnimator(animate, onEnd = onEnd)
|
||||
animator.playTogether(createAnimators(::createWelcomeProperties))
|
||||
leapfrogWidget.fold { animator.start() }
|
||||
}
|
||||
|
||||
fun toFolded(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
fun toFolded(
|
||||
animate: Boolean = true,
|
||||
duration: Long = animDuration,
|
||||
onEnd: () -> Unit = {},
|
||||
) {
|
||||
if (currentState == WidgetState.FOLDED) return
|
||||
|
||||
currentState = WidgetState.FOLDED
|
||||
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createLeapfrogProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createLeapfrogProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createLeapfrogProperties(BackupCardType.SECOND_BACKUP)),
|
||||
)
|
||||
leapfrogWidget.fold(animate) { animator.start() }
|
||||
val animator = createAnimator(animate, duration) {
|
||||
leapfrogWidget.fold(animate, onEnd)
|
||||
}
|
||||
animator.playTogether(createAnimators(::createLeapfrogProperties))
|
||||
animator.start()
|
||||
}
|
||||
|
||||
fun toFan(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
fun toFan(
|
||||
animate: Boolean = true,
|
||||
onEnd: () -> Unit = {},
|
||||
) {
|
||||
if (currentState == WidgetState.FAN) return
|
||||
|
||||
currentState = WidgetState.FAN
|
||||
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createFanProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createFanProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createFanProperties(BackupCardType.SECOND_BACKUP)),
|
||||
)
|
||||
val animator = createAnimator(animate, onEnd = onEnd)
|
||||
animator.playTogether(createAnimators(::createFanProperties))
|
||||
leapfrogWidget.fold { animator.start() }
|
||||
}
|
||||
|
||||
fun toLeapfrog(animate: Boolean = true, onEnd: () -> Unit = {}) {
|
||||
fun toLeapfrog(
|
||||
animate: Boolean = true,
|
||||
onEndFold: () -> Unit = {},
|
||||
onEnd: () -> Unit = {},
|
||||
) {
|
||||
if (currentState == WidgetState.LEAPFROG) return
|
||||
|
||||
currentState = WidgetState.LEAPFROG
|
||||
|
||||
val animator = createAnimator(animate, onEnd)
|
||||
animator.playTogether(
|
||||
createAnimator(BackupCardType.ORIGIN, createLeapfrogProperties(BackupCardType.ORIGIN)),
|
||||
createAnimator(BackupCardType.FIRST_BACKUP, createLeapfrogProperties(BackupCardType.FIRST_BACKUP)),
|
||||
createAnimator(BackupCardType.SECOND_BACKUP, createLeapfrogProperties(BackupCardType.SECOND_BACKUP)),
|
||||
)
|
||||
leapfrogWidget.fold {
|
||||
animator.doOnEnd {
|
||||
val onAnimatorEnd = {
|
||||
leapfrogWidget.fold(animate) {
|
||||
leapfrogWidget.initViews()
|
||||
leapfrogWidget.unfold()
|
||||
onEndFold()
|
||||
leapfrogWidget.unfold(animate, onEnd)
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
val animator = createAnimator(animate, onEnd = onAnimatorEnd)
|
||||
animator.playTogether(createAnimators(::createLeapfrogProperties))
|
||||
animator.start()
|
||||
}
|
||||
|
||||
private fun createAnimator(animate: Boolean, onEnd: () -> Unit): AnimatorSet {
|
||||
private fun createAnimators(propertyFactory: (BackupCardType) -> CardProperties): List<ObjectAnimator> {
|
||||
return getCardTypesTypes().map { createCardAnimator(it, propertyFactory(it)) }
|
||||
}
|
||||
|
||||
private fun getCardTypesTypes(): List<BackupCardType> = when (leapfrogWidget.getViewsCount()) {
|
||||
2 -> listOf(BackupCardType.ORIGIN, BackupCardType.FIRST_BACKUP)
|
||||
3 -> listOf(BackupCardType.ORIGIN, BackupCardType.FIRST_BACKUP, BackupCardType.SECOND_BACKUP)
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
private fun createAnimator(animate: Boolean, duration: Long = animDuration, onEnd: () -> Unit): AnimatorSet {
|
||||
return AnimatorSet().apply {
|
||||
duration = if (animate) animDuration else 0
|
||||
this.duration = if (animate) duration else 0
|
||||
doOnEnd { onEnd() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAnimator(
|
||||
private fun createCardAnimator(
|
||||
cardType: BackupCardType,
|
||||
properties: CardProperties,
|
||||
): ObjectAnimator {
|
||||
val view = getLeapViewByCardNumber(cardType).view
|
||||
val animator =
|
||||
ObjectAnimator.ofPropertyValuesHolder(
|
||||
view,
|
||||
*properties.createValuesHolders().toTypedArray(),
|
||||
)
|
||||
val view = getLeapViewByCard(cardType).view
|
||||
val animator = ObjectAnimator.ofPropertyValuesHolder(
|
||||
view,
|
||||
*properties.createValuesHolders().toTypedArray(),
|
||||
)
|
||||
view.elevation = properties.elevation
|
||||
return animator
|
||||
}
|
||||
|
|
@ -181,7 +194,7 @@ class WalletCardsWidget(
|
|||
|
||||
private fun createActivateProperties(cardType: BackupCardType): CardProperties {
|
||||
val topOfAnchorView = getTopOfAnchorViewForActivateState()
|
||||
val twinProperties = CardProperties.from(getLeapViewByCardNumber(cardType).state)
|
||||
val twinProperties = CardProperties.from(getLeapViewByCard(cardType).state)
|
||||
return twinProperties.copy(
|
||||
xTranslation = twinProperties.xTranslation,
|
||||
yTranslation = twinProperties.yTranslation - topOfAnchorView,
|
||||
|
|
@ -190,24 +203,40 @@ class WalletCardsWidget(
|
|||
)
|
||||
}
|
||||
|
||||
private fun getLeapViewByCardNumber(cardType: BackupCardType): LeapView {
|
||||
return when (cardType) {
|
||||
BackupCardType.ORIGIN -> leapfrogWidget.getViewByPosition(0)
|
||||
BackupCardType.FIRST_BACKUP -> leapfrogWidget.getViewByPosition(1)
|
||||
BackupCardType.SECOND_BACKUP -> leapfrogWidget.getViewByPosition(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(UnsupportedOperationException::class)
|
||||
fun getOriginCardView(): ImageView {
|
||||
return getLeapViewByCardNumber(BackupCardType.ORIGIN).view as ImageView
|
||||
return getLeapViewByCard(BackupCardType.ORIGIN).view as ImageView
|
||||
}
|
||||
|
||||
@Throws(UnsupportedOperationException::class)
|
||||
fun getFirstBackupCardView(): ImageView {
|
||||
return getLeapViewByCardNumber(BackupCardType.FIRST_BACKUP).view as ImageView
|
||||
return getLeapViewByCard(BackupCardType.FIRST_BACKUP).view as ImageView
|
||||
}
|
||||
|
||||
@Throws(UnsupportedOperationException::class)
|
||||
fun getSecondBackupCardView(): ImageView {
|
||||
return getLeapViewByCardNumber(BackupCardType.SECOND_BACKUP).view as ImageView
|
||||
return getLeapViewByCard(BackupCardType.SECOND_BACKUP).view as ImageView
|
||||
}
|
||||
|
||||
@Throws(UnsupportedOperationException::class)
|
||||
private fun getLeapViewByCard(cardType: BackupCardType): LeapView {
|
||||
fun getByIndex(index: Int): LeapView {
|
||||
return leapfrogWidget.getViewByPosition(leapfrogWidget.getViewPositionByIndex(index))
|
||||
}
|
||||
|
||||
return when (leapfrogWidget.getViewsCount()) {
|
||||
2 -> when (cardType) {
|
||||
BackupCardType.ORIGIN -> getByIndex(1)
|
||||
BackupCardType.FIRST_BACKUP -> getByIndex(0)
|
||||
BackupCardType.SECOND_BACKUP -> throw UnsupportedOperationException()
|
||||
}
|
||||
3 -> when (cardType) {
|
||||
BackupCardType.ORIGIN -> getByIndex(2)
|
||||
BackupCardType.FIRST_BACKUP -> getByIndex(1)
|
||||
BackupCardType.SECOND_BACKUP -> getByIndex(0)
|
||||
}
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
enum class WidgetState { WELCOME, FOLDED, FAN, LEAPFROG }
|
||||
|
|
|
|||
10
app/src/main/res/layout/view_onboarding_card.xml
Normal file
10
app/src/main/res/layout/view_onboarding_card.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.AppCompatImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/card_placeholder_black"
|
||||
android:transitionName="imv_front_card" />
|
||||
Loading…
Add table
Add a link
Reference in a new issue