diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index b0de1e9949..99ce6f4280 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -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 { +class OnboardingOtherCardsFragment : BaseOnboardingFragment() { - 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 {} \ No newline at end of file + 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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt new file mode 100644 index 0000000000..effdecff73 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt @@ -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() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt new file mode 100644 index 0000000000..d781c5b1cb --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt @@ -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 = { 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)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt new file mode 100644 index 0000000000..316f97f636 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsState.kt new file mode 100644 index 0000000000..bcf232bd85 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsState.kt @@ -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.values().toList(), +) : StateType { + + val progress: Int + get() = steps.indexOf(currentStep) +} + +enum class OnboardingOtherCardsStep { + None, CreateWallet, Done +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/service/OnboardingOtherCardsService.kt b/app/src/main/java/com/tangem/tap/features/onboarding/service/OnboardingOtherCardsService.kt new file mode 100644 index 0000000000..5e81842312 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/service/OnboardingOtherCardsService.kt @@ -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() + } +} \ No newline at end of file