Updated on 2026-08-14
This commit is contained in:
parent
ccb8afe104
commit
fe42b821db
6 changed files with 287 additions and 18 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue