Updated on 2026-08-14

This commit is contained in:
Tangem 2021-10-13 18:57:29 +03:00
parent ccb8afe104
commit fe42b821db
6 changed files with 287 additions and 18 deletions

View file

@ -2,40 +2,97 @@ package com.tangem.tap.features.onboarding.products.otherCards
import android.os.Bundle
import android.view.View
import androidx.transition.TransitionInflater
import com.tangem.tap.features.send.BaseStoreFragment
import android.view.animation.OvershootInterpolator
import androidx.annotation.LayoutRes
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.isVisible
import androidx.transition.TransitionManager
import com.tangem.tap.common.extensions.getDrawableCompat
import com.tangem.tap.common.transitions.InternalNoteLayoutTransition
import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsAction
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsState
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsStep
import com.tangem.tap.store
import com.tangem.wallet.R
import org.rekotlin.StoreSubscriber
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.*
/**
[REDACTED_AUTHOR]
*/
class OnboardingOtherCardsFragment : BaseStoreFragment(R.layout.fragment_onboarding_main), StoreSubscriber<OnboardingOtherCardsState> {
class OnboardingOtherCardsFragment : BaseOnboardingFragment<OnboardingOtherCardsState>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.fade)
exitTransition = inflater.inflateTransition(R.transition.fade)
}
override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_note
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
store.dispatch(OnboardingOtherCardsAction.DetermineStepOfScreen)
}
override fun subscribeToStore() {
// store.subscribe(this) { state ->
// state.skipRepeats { oldState, newState ->
// oldState.onboardingOtherState == newState.onboardingOtherState
// }.select { it.onboardingOtherState }
// }
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.onboardingOtherCardsState == newState.onboardingOtherCardsState
}.select { it.onboardingOtherCardsState }
}
storeSubscribersList.add(this)
}
override fun newState(state: OnboardingOtherCardsState) {
if (activity == null) return
if (state.currentStep == OnboardingOtherCardsStep.None) return
state.artworkBitmap?.let { imv_front_card.setImageBitmap(it) }
pb_state.max = state.steps.size - 1
pb_state.progress = state.progress
when (state.currentStep) {
OnboardingOtherCardsStep.CreateWallet -> setupCreateWalletState(state)
OnboardingOtherCardsStep.Done -> setupDoneState(state)
}
showConfetti(state.showConfetti)
}
}
class OnboardingOtherCardsState {}
private fun setupCreateWalletState(state: OnboardingOtherCardsState) {
btn_main_action.setText(R.string.onboarding_create_wallet_button_create_wallet)
btn_main_action.setOnClickListener { store.dispatch(OnboardingOtherCardsAction.CreateWallet) }
btn_alternative_action.setText(R.string.onboarding_button_what_does_it_mean)
btn_alternative_action.setOnClickListener { }
tv_header.setText(R.string.onboarding_create_wallet_header)
tv_body.setText(R.string.onboarding_create_wallet_body)
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_circle))
updateConstraints(R.layout.lp_onboarding_create_wallet)
}
private fun setupDoneState(state: OnboardingOtherCardsState) {
btn_main_action.setText(R.string.onboarding_done_button_continue)
btn_main_action.setOnClickListener {
showConfetti(false)
store.dispatch(OnboardingOtherCardsAction.Done)
}
btn_alternative_action.isVisible = false
btn_alternative_action.setText("")
btn_alternative_action.setOnClickListener { }
tv_header.setText(R.string.onboarding_done_header)
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)
}
private fun updateConstraints(@LayoutRes layoutId: Int) {
val constraintSet = ConstraintSet()
constraintSet.clone(requireContext(), layoutId)
constraintSet.applyTo(onboarding_main_container)
val transition = InternalNoteLayoutTransition()
transition.interpolator = OvershootInterpolator()
TransitionManager.beginDelayedTransition(onboarding_main_container, transition)
}
}

View file

@ -0,0 +1,22 @@
package com.tangem.tap.features.onboarding.products.otherCards.redux
import org.rekotlin.Action
/**
[REDACTED_AUTHOR]
*/
sealed class OnboardingOtherCardsAction : Action {
// from user, ui
object CreateWallet : OnboardingOtherCardsAction()
// from redux
object DetermineStepOfScreen : OnboardingOtherCardsAction()
object Done : OnboardingOtherCardsAction()
data class SetStepOfScreen(val step: OnboardingOtherCardsStep) : OnboardingOtherCardsAction()
sealed class Confetti {
object Show : OnboardingOtherCardsAction()
object Hide : OnboardingOtherCardsAction()
}
}

View file

@ -0,0 +1,81 @@
package com.tangem.tap.features.onboarding.products.otherCards.redux
import com.tangem.common.CompletionResult
import com.tangem.tap.common.extensions.withMainContext
import com.tangem.tap.common.postUi
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
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.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.Middleware
class OnboardingOtherCardsMiddleware {
companion object {
val handler = onboardingOtherCardsMiddleware
}
}
private val onboardingOtherCardsMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
handleOtherCardsAction(action)
next(action)
}
}
}
private fun handleOtherCardsAction(action: Action) {
if (action !is OnboardingOtherCardsAction) return
val service = store.state.onboardingOtherCardsState.onboardingService ?: return
val noteState = store.state.onboardingOtherCardsState
when (action) {
is OnboardingOtherCardsAction.DetermineStepOfScreen -> {
val step = when {
service.walletManager == null -> OnboardingOtherCardsStep.CreateWallet
else -> OnboardingOtherCardsStep.Done
}
store.dispatch((OnboardingOtherCardsAction.SetStepOfScreen(step)))
}
is OnboardingOtherCardsAction.SetStepOfScreen -> {
if (action.step == OnboardingOtherCardsStep.Done) {
service.activationFinished()
postUi(500) { store.dispatch(OnboardingOtherCardsAction.Confetti.Show) }
}
}
is OnboardingOtherCardsAction.CreateWallet -> {
scope.launch {
val result = tangemSdkManager.createProductWallet(service.scanResponse)
withMainContext {
when (result) {
is CompletionResult.Success -> {
val updatedResponse = service.scanResponse.copy(card = result.data)
service.scanResponse = updatedResponse
service.activationStarted()
delay(DELAY_SDK_DIALOG_CLOSE)
store.dispatch(OnboardingOtherCardsAction.SetStepOfScreen(OnboardingOtherCardsStep.Done))
}
is CompletionResult.Failure -> {
// do nothing
}
}
}
}
}
OnboardingOtherCardsAction.Done -> {
store.dispatch(GlobalAction.Onboarding.Deactivate)
scope.launch {
store.state.globalState.tapWalletManager.onCardScanned(service.scanResponse)
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
}
}
}
}

View file

@ -0,0 +1,45 @@
package com.tangem.tap.features.onboarding.products.otherCards.redux
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.onboarding.service.OnboardingOtherCardsService
import org.rekotlin.Action
class OnboardingOtherCardsReducer {
companion object {
fun reduce(action: Action, state: AppState): OnboardingOtherCardsState = internalReduce(action, state)
}
}
private fun internalReduce(action: Action, appState: AppState): OnboardingOtherCardsState {
var state = appState.onboardingOtherCardsState
when (action) {
is GlobalAction.Onboarding.Activate -> {
if (action.onboardingService is OnboardingOtherCardsService) {
val service = action.onboardingService
state = state.copy(
onboardingService = service,
artworkBitmap = service.getArtwork().value?.artwork,
showConfetti = false
)
}
}
GlobalAction.Onboarding.Deactivate -> {
state = OnboardingOtherCardsState()
}
is OnboardingOtherCardsAction.SetStepOfScreen -> {
if (action.step != state.currentStep && state.steps.contains(action.step)) {
state = state.copy(currentStep = action.step)
}
}
is OnboardingOtherCardsAction.Confetti.Show -> {
state = state.copy(showConfetti = true)
}
is OnboardingOtherCardsAction.Confetti.Hide -> {
state = state.copy(showConfetti = false)
}
}
return state
}

View file

@ -0,0 +1,25 @@
package com.tangem.tap.features.onboarding.products.otherCards.redux
import android.graphics.Bitmap
import com.tangem.tap.features.onboarding.service.OnboardingOtherCardsService
import org.rekotlin.StateType
/**
[REDACTED_AUTHOR]
*/
data class OnboardingOtherCardsState(
val onboardingService: OnboardingOtherCardsService? = null,
// UI
val showConfetti: Boolean = false,
val artworkBitmap: Bitmap? = null,
val currentStep: OnboardingOtherCardsStep = OnboardingOtherCardsStep.None,
val steps: List<OnboardingOtherCardsStep> = OnboardingOtherCardsStep.values().toList(),
) : StateType {
val progress: Int
get() = steps.indexOf(currentStep)
}
enum class OnboardingOtherCardsStep {
None, CreateWallet, Done
}

View file

@ -0,0 +1,39 @@
package com.tangem.tap.features.onboarding.service
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.tap.common.extensions.withMainContext
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.tasks.product.ScanResponse
import com.tangem.tap.features.wallet.redux.AddressData
import com.tangem.tap.persistence.UsedCardsPrefStorage
/**
[REDACTED_AUTHOR]
*/
class OnboardingOtherCardsService(
override val fromScreen: AppScreen,
override var scanResponse: ScanResponse,
cardInfoStorage: UsedCardsPrefStorage,
walletManagerFactory: WalletManagerFactory,
) : ProductOnboardingService(cardInfoStorage, walletManagerFactory) {
override fun navigateToScreen(): AppScreen {
return AppScreen.OnboardingOther
}
// Return any value and any state. The balance of the card is not important in this service
override suspend fun updateBalance(): OnboardingWalletBalance {
val customError = TapError.CustomError("Loading cancelled. Cause: wallet manager didn't created")
withMainContext { loadedBalance = OnboardingWalletBalance.error(customError) }
return loadedBalance
}
override fun getToUpUrl(): String? {
throw UnsupportedOperationException()
}
override fun getAddressData(): AddressData? {
throw UnsupportedOperationException()
}
}