Updated on 2026-08-14
This commit is contained in:
parent
99f1b91bae
commit
a7fc5e1036
38 changed files with 1486 additions and 195 deletions
|
|
@ -16,9 +16,12 @@ import com.tangem.tap.features.details.ui.walletconnect.QrScanFragment
|
|||
import com.tangem.tap.features.details.ui.walletconnect.WalletConnectSessionsFragment
|
||||
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
|
||||
import com.tangem.tap.features.home.HomeFragment
|
||||
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
|
||||
import com.tangem.tap.features.onboarding.products.old.OnboardingOtherCardsFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.OnboardingWalletFragment
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.tokens.ui.AddTokensFragment
|
||||
import com.tangem.tap.features.wallet.ui.TwinsOnboardingFragment
|
||||
import com.tangem.tap.features.wallet.ui.OnboardingTwinsFragment
|
||||
import com.tangem.tap.features.wallet.ui.WalletDetailsFragment
|
||||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -67,6 +70,10 @@ fun FragmentActivity.addOnBackPressedDispatcher(
|
|||
private fun fragmentFactory(screen: AppScreen): Fragment {
|
||||
return when (screen) {
|
||||
AppScreen.Home -> HomeFragment()
|
||||
AppScreen.OnboardingNote -> OnboardingNoteFragment()
|
||||
AppScreen.OnboardingWallet -> OnboardingWalletFragment()
|
||||
AppScreen.OnboardingTwins -> OnboardingTwinsFragment()
|
||||
AppScreen.OnboardingOther -> OnboardingOtherCardsFragment()
|
||||
AppScreen.Wallet -> WalletFragment()
|
||||
AppScreen.Send -> SendFragment()
|
||||
AppScreen.Details -> DetailsFragment()
|
||||
|
|
@ -75,7 +82,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
|
|||
AppScreen.Disclaimer -> DisclaimerFragment()
|
||||
AppScreen.CreateTwinWalletWarning -> TwinWalletWarningFragment()
|
||||
AppScreen.CreateTwinWallet -> CreateTwinWalletFragment()
|
||||
AppScreen.TwinsOnboarding -> TwinsOnboardingFragment()
|
||||
AppScreen.AddTokens -> AddTokensFragment()
|
||||
AppScreen.WalletDetails -> WalletDetailsFragment()
|
||||
AppScreen.WalletConnectSessions -> WalletConnectSessionsFragment()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import com.tangem.tap.features.details.redux.DetailsReducer
|
|||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerReducer
|
||||
import com.tangem.tap.features.home.redux.HomeReducer
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteReducer
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletReducer
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingReducer
|
||||
import com.tangem.tap.features.send.redux.reducers.SendScreenReducer
|
||||
import com.tangem.tap.features.tokens.redux.TokensReducer
|
||||
import com.tangem.tap.features.wallet.redux.reducers.WalletReducer
|
||||
|
|
@ -19,6 +22,9 @@ fun appReducer(action: Action, state: AppState?): AppState {
|
|||
navigationState = NavigationReducer.reduce(action, state),
|
||||
globalState = globalReducer(action, state),
|
||||
homeState = HomeReducer.reduce(action, state),
|
||||
onboardingState = OnboardingReducer.reduce(action, state),
|
||||
onboardingNoteState = OnboardingNoteReducer.reduce(action, state),
|
||||
onboardingWalletState = OnboardingWalletReducer.reduce(action, state),
|
||||
walletState = WalletReducer.reduce(action, state),
|
||||
sendState = SendScreenReducer.reduce(action, state.sendState),
|
||||
detailsState = DetailsReducer.reduce(action, state),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.common.redux.global.GlobalMiddleware
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.redux.global.globalMiddleware
|
||||
import com.tangem.tap.common.redux.navigation.NavigationState
|
||||
import com.tangem.tap.common.redux.navigation.navigationMiddleware
|
||||
import com.tangem.tap.features.details.redux.DetailsMiddleware
|
||||
|
|
@ -12,6 +12,12 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerMiddleware
|
|||
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
|
||||
import com.tangem.tap.features.home.redux.HomeMiddleware
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteMiddleware
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteState
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletMiddleware
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingMiddleware
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingState
|
||||
import com.tangem.tap.features.send.redux.middlewares.SendMiddleware
|
||||
import com.tangem.tap.features.send.redux.states.SendState
|
||||
import com.tangem.tap.features.tokens.redux.TokensMiddleware
|
||||
|
|
@ -25,6 +31,9 @@ data class AppState(
|
|||
val navigationState: NavigationState = NavigationState(),
|
||||
val globalState: GlobalState = GlobalState(),
|
||||
val homeState: HomeState = HomeState(),
|
||||
val onboardingState: OnboardingState = OnboardingState(),
|
||||
val onboardingNoteState: OnboardingNoteState = OnboardingNoteState(),
|
||||
val onboardingWalletState: OnboardingWalletState = OnboardingWalletState(),
|
||||
val walletState: WalletState = WalletState(),
|
||||
val sendState: SendState = SendState(),
|
||||
val detailsState: DetailsState = DetailsState(),
|
||||
|
|
@ -36,8 +45,12 @@ data class AppState(
|
|||
companion object {
|
||||
fun getMiddleware(): List<Middleware<AppState>> {
|
||||
return listOf(
|
||||
logMiddleware, navigationMiddleware, notificationsMiddleware, globalMiddleware,
|
||||
HomeMiddleware().homeMiddleware,
|
||||
logMiddleware, navigationMiddleware, notificationsMiddleware,
|
||||
GlobalMiddleware.handler,
|
||||
HomeMiddleware.handler,
|
||||
OnboardingMiddleware.handler,
|
||||
OnboardingNoteMiddleware.handler,
|
||||
OnboardingWalletMiddleware.handler,
|
||||
WalletMiddleware().walletMiddleware,
|
||||
SendMiddleware().sendMiddleware,
|
||||
DetailsMiddleware().detailsMiddleware,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.tangem.tap.common.redux.global
|
|||
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.tap.common.redux.DebugErrorAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
|
|
@ -14,6 +17,14 @@ import org.rekotlin.Action
|
|||
|
||||
sealed class GlobalAction : Action {
|
||||
|
||||
data class DebugShowError(override val error: TapError) : GlobalAction(), DebugErrorAction
|
||||
|
||||
data class ReadCard(
|
||||
val onSuccess: (suspend (ScanNoteResponse) -> Unit)? = null,
|
||||
val onFailure: (suspend (TangemError) -> Unit)? = null,
|
||||
val messageResId: Int? = null,
|
||||
) : GlobalAction()
|
||||
|
||||
object ScanFailsCounter {
|
||||
data class ChooseBehavior(val result: CompletionResult<ScanNoteResponse>) : GlobalAction()
|
||||
object Reset : GlobalAction()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.common.redux.global
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
|
|
@ -13,10 +14,19 @@ import com.tangem.tap.network.moonpay.MoonpayService
|
|||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
val globalMiddleware: Middleware<AppState> = { dispatch, appState ->
|
||||
class GlobalMiddleware {
|
||||
companion object {
|
||||
val handler = globalMiddlewareHandler
|
||||
}
|
||||
}
|
||||
|
||||
private val globalMiddlewareHandler: Middleware<AppState> = { dispatch, appState ->
|
||||
{ nextDispatch ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
|
|
@ -78,6 +88,21 @@ val globalMiddleware: Middleware<AppState> = { dispatch, appState ->
|
|||
}
|
||||
}
|
||||
}
|
||||
is GlobalAction.ReadCard -> {
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler, action.messageResId)
|
||||
withContext(Dispatchers.Main) {
|
||||
store.dispatch(GlobalAction.ScanFailsCounter.ChooseBehavior(result))
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data.card)
|
||||
action.onSuccess?.invoke(result.data)
|
||||
}
|
||||
is CompletionResult.Failure -> action.onFailure?.invoke(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nextDispatch(action)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.tangem.tap.common.redux.navigation
|
|||
|
||||
import android.view.View
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.ChangeImageTransform
|
||||
import androidx.transition.ChangeTransform
|
||||
import androidx.transition.TransitionSet
|
||||
import org.rekotlin.Action
|
||||
import java.lang.ref.WeakReference
|
||||
|
|
@ -27,4 +30,14 @@ data class FragmentShareTransition(
|
|||
val exitTransitionSet: TransitionSet
|
||||
)
|
||||
|
||||
data class ShareElement(val wView: WeakReference<View>, val name: String)
|
||||
data class ShareElement(val wView: WeakReference<View>, val name: String)
|
||||
|
||||
//TODO: remove transition example
|
||||
class DetailsTransition : TransitionSet() {
|
||||
init {
|
||||
ordering = ORDERING_TOGETHER;
|
||||
addTransition(ChangeBounds())
|
||||
.addTransition(ChangeTransform())
|
||||
.addTransition(ChangeImageTransform())
|
||||
}
|
||||
}
|
||||
|
|
@ -5,12 +5,19 @@ import org.rekotlin.StateType
|
|||
import java.lang.ref.WeakReference
|
||||
|
||||
data class NavigationState(
|
||||
val backStack: List<AppScreen> = listOf(AppScreen.Home),
|
||||
val activity: WeakReference<FragmentActivity>? = null
|
||||
val backStack: List<AppScreen> = listOf(AppScreen.Home),
|
||||
val activity: WeakReference<FragmentActivity>? = null
|
||||
) : StateType
|
||||
|
||||
enum class AppScreen {
|
||||
Home, Wallet, WalletDetails, Send, Details, DetailsConfirm, DetailsSecurity, Disclaimer,
|
||||
CreateTwinWalletWarning, CreateTwinWallet, TwinsOnboarding, AddTokens, WalletConnectSessions,
|
||||
Home,
|
||||
Disclaimer,
|
||||
OnboardingNote, OnboardingWallet, OnboardingTwins, OnboardingOther,
|
||||
Wallet, WalletDetails,
|
||||
Send,
|
||||
Details, DetailsConfirm, DetailsSecurity,
|
||||
CreateTwinWalletWarning, CreateTwinWallet,
|
||||
AddTokens,
|
||||
WalletConnectSessions,
|
||||
QrScan
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
import com.tangem.tap.common.post
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Middleware
|
||||
|
|
@ -14,16 +15,10 @@ class DisclaimerMiddleware {
|
|||
when (action) {
|
||||
is DisclaimerAction.AcceptDisclaimer -> {
|
||||
preferencesStorage.saveDisclaimerAccepted()
|
||||
if (store.state.walletState.twinCardsState != null) {
|
||||
val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown()
|
||||
if (showOnboarding) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding))
|
||||
} else {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
}
|
||||
} else {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
}
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
|
||||
//delayed sending used for better animation
|
||||
post(550) { store.dispatch(HomeAction.ReadCard) }
|
||||
}
|
||||
}
|
||||
next(action)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
package com.tangem.tap.features.home
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.extensions.safeStartActivity
|
||||
import com.tangem.tap.common.extensions.toast
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.common.redux.navigation.DetailsTransition
|
||||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import com.tangem.tap.common.redux.navigation.ShareElement
|
||||
import com.tangem.tap.common.toggleWidget.IndeterminateProgressButtonWidget
|
||||
import com.tangem.tap.common.toggleWidget.ViewStateWidget
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeDialog
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
|
|
@ -15,11 +23,36 @@ import com.tangem.tap.store
|
|||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import org.rekotlin.StoreSubscriber
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState> {
|
||||
|
||||
lateinit var btnScanCard: ViewStateWidget
|
||||
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val transitionViews = mutableListOf<ShareElement>()
|
||||
transitionViews.add(ShareElement(WeakReference(imv_front_card), "imv_front_card"))
|
||||
val shareTransition = FragmentShareTransition(transitionViews, DetailsTransition(), DetailsTransition())
|
||||
|
||||
store.dispatch(HomeAction.SetFragmentShareTransition(shareTransition))
|
||||
store.dispatch(HomeAction.Init)
|
||||
|
||||
btn_scan_card?.setOnClickListener { store.dispatch(HomeAction.ReadCard) }
|
||||
btn_get_new_card?.setOnClickListener { store.dispatch(HomeAction.GoToShop) }
|
||||
|
||||
btnScanCard = IndeterminateProgressButtonWidget(btn_scan_card, progress)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
|
|
@ -37,16 +70,23 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
|
||||
override fun newState(state: HomeState) {
|
||||
if (activity == null) return
|
||||
if (state.firstLaunch) {
|
||||
tv_home_description.text = getText(R.string.home_welcome)
|
||||
btn_shop.text = getText(R.string.common_no)
|
||||
btn_yes.text = getText(R.string.home_button_yes)
|
||||
} else {
|
||||
tv_home_description.text = getText(R.string.home_welcome_back)
|
||||
btn_shop.text = getText(R.string.home_button_shop)
|
||||
btn_yes.text = getText(R.string.home_button_scan)
|
||||
}
|
||||
|
||||
handleOpenUrl(state)
|
||||
handleDialog(state.dialog)
|
||||
|
||||
btnScanCard.changeState(state.btnScanState.progressState)
|
||||
btnScanCard.mainView.isEnabled = state.btnScanState.enabled
|
||||
}
|
||||
|
||||
private fun handleOpenUrl(state: HomeState) {
|
||||
if (state.openUrl == null) return
|
||||
val context = context ?: return
|
||||
|
||||
val uri = Uri.parse(state.openUrl)
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
context.safeStartActivity(intent, null, { toast(it.toString()) }, {
|
||||
store.dispatch(HomeAction.SetOpenUrl(null))
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleDialog(stateDialog: StateDialog?) {
|
||||
|
|
@ -61,19 +101,8 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
btn_yes?.setOnClickListener { store.dispatch(HomeAction.ReadCard) }
|
||||
btn_shop?.setOnClickListener { store.dispatch(HomeAction.GoToShop(requireContext())) }
|
||||
|
||||
store.dispatch(GlobalAction.GetMoonPayUserStatus)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
override fun onDestroyView() {
|
||||
store.dispatch(HomeAction.SetFragmentShareTransition(null))
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,22 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class HomeAction : Action {
|
||||
object Init : HomeAction()
|
||||
data class SetFragmentShareTransition(val shareTransition: FragmentShareTransition?) : HomeAction()
|
||||
|
||||
object ReadCard : HomeAction()
|
||||
data class GoToShop(val context: Context) : HomeAction()
|
||||
object CheckIfFirstLaunch : HomeAction() {
|
||||
data class Result(val firstLaunch: Boolean) : HomeAction()
|
||||
}
|
||||
object GoToShop : HomeAction()
|
||||
class SetOpenUrl(val url: String?) : HomeAction()
|
||||
class SetTermsOfUseState(val isDisclaimerAccepted: Boolean) : HomeAction()
|
||||
|
||||
data class ChangeScanCardButtonState(val state: IndeterminateProgressButton) : HomeAction()
|
||||
|
||||
object ShowDialog : HomeAction() {
|
||||
object ScanFails : HomeAction()
|
||||
}
|
||||
|
||||
object HideDialog : HomeAction()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +1,82 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
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.TapError
|
||||
import com.tangem.tap.features.onboarding.OnboardingService
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingAction
|
||||
import com.tangem.tap.features.send.redux.states.ButtonState
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class HomeMiddleware {
|
||||
val homeMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
is HomeAction.CheckIfFirstLaunch -> {
|
||||
store.dispatch(
|
||||
HomeAction.CheckIfFirstLaunch.Result(preferencesStorage.getCountOfLaunches() == 1)
|
||||
)
|
||||
}
|
||||
is HomeAction.ReadCard -> {
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler)
|
||||
withContext(Dispatchers.Main) {
|
||||
store.dispatch(GlobalAction.ScanFailsCounter.ChooseBehavior(result))
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data.card)
|
||||
store.dispatch(GlobalAction.RestoreAppCurrency)
|
||||
store.state.globalState.tapWalletManager.onCardScanned(result.data)
|
||||
showDisclaimerOrNavigateToWallet()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is HomeAction.GoToShop -> {
|
||||
val uri = Uri.parse(CARD_SHOP_URI)
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
startActivity(action.context, intent, null)
|
||||
}
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDisclaimerOrNavigateToWallet() {
|
||||
if (!preferencesStorage.wasDisclaimerAccepted()) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
|
||||
return
|
||||
}
|
||||
if (store.state.walletState.twinCardsState != null) {
|
||||
val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown()
|
||||
if (showOnboarding) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding))
|
||||
return
|
||||
}
|
||||
}
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CARD_SHOP_URI =
|
||||
val handler = homeMiddleware
|
||||
|
||||
const val CARD_SHOP_URI =
|
||||
"https://shop.tangem.com/?afmc=1i&utm_campaign=1i&utm_source=leaddyno&utm_medium=affiliate"
|
||||
}
|
||||
}
|
||||
|
||||
private val homeMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
is HomeAction.Init -> {
|
||||
store.dispatch(GlobalAction.RestoreAppCurrency)
|
||||
store.dispatch(GlobalAction.GetMoonPayUserStatus)
|
||||
store.dispatch(HomeAction.SetTermsOfUseState(preferencesStorage.wasDisclaimerAccepted()))
|
||||
}
|
||||
is HomeAction.ReadCard -> {
|
||||
if (!preferencesStorage.wasDisclaimerAccepted()) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
|
||||
} else {
|
||||
launchOnboardingService()
|
||||
}
|
||||
}
|
||||
is HomeAction.GoToShop -> store.dispatch(HomeAction.SetOpenUrl(HomeMiddleware.CARD_SHOP_URI))
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchOnboardingService() {
|
||||
fun changeButtonState(state: ButtonState) {
|
||||
val btnState = IndeterminateProgressButton(state)
|
||||
store.dispatch(HomeAction.ChangeScanCardButtonState(btnState))
|
||||
}
|
||||
changeButtonState(ButtonState.PROGRESS)
|
||||
|
||||
val walletManager = store.state.globalState.tapWalletManager
|
||||
val service = OnboardingService(
|
||||
walletManager,
|
||||
preferencesStorage.usedCardsPrefStorage
|
||||
)
|
||||
|
||||
service.onReadyToProceed = {
|
||||
store.dispatch(OnboardingAction.SetData(it))
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
store.dispatch(NavigationAction.NavigateTo(it.onboardingScreen))
|
||||
}
|
||||
|
||||
service.onFailedToProceedToOnboardingCase = {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
walletManager.onCardScanned(it)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
}
|
||||
|
||||
service.onError = {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
store.dispatch(GlobalAction.DebugShowError(TapError.CustomError(it)))
|
||||
}
|
||||
|
||||
store.dispatch(GlobalAction.ReadCard(service::onSuccess, {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
store.dispatch(GlobalAction.DebugShowError(TapError.ScanCardError))
|
||||
}))
|
||||
}
|
||||
|
|
@ -13,18 +13,27 @@ private fun internalReduce(action: Action, state: AppState): HomeState {
|
|||
|
||||
if (action !is HomeAction) return state.homeState
|
||||
|
||||
var homeState = state.homeState
|
||||
var state = state.homeState
|
||||
when (action) {
|
||||
is HomeAction.CheckIfFirstLaunch.Result -> {
|
||||
homeState = homeState.copy(firstLaunch = action.firstLaunch)
|
||||
is HomeAction.SetFragmentShareTransition -> {
|
||||
state = state.copy(shareTransition = action.shareTransition)
|
||||
}
|
||||
is HomeAction.SetTermsOfUseState -> {
|
||||
state = state.copy(isDisclaimerAccepted = action.isDisclaimerAccepted)
|
||||
}
|
||||
is HomeAction.SetOpenUrl -> {
|
||||
state = state.copy(openUrl = action.url)
|
||||
}
|
||||
is HomeAction.ChangeScanCardButtonState -> {
|
||||
state = state.copy(btnScanState = action.state)
|
||||
}
|
||||
is HomeAction.ShowDialog.ScanFails -> {
|
||||
homeState = homeState.copy(dialog = HomeDialog.ScanFailsDialog)
|
||||
state = state.copy(dialog = HomeDialog.ScanFailsDialog)
|
||||
}
|
||||
is HomeAction.HideDialog -> {
|
||||
homeState = homeState.copy(dialog = null)
|
||||
state = state.copy(dialog = null)
|
||||
}
|
||||
}
|
||||
|
||||
return homeState
|
||||
return state
|
||||
}
|
||||
|
|
@ -1,13 +1,19 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import com.tangem.tap.features.send.redux.states.ButtonState
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class HomeState(
|
||||
val firstLaunch: Boolean = true,
|
||||
val dialog: StateDialog? = null
|
||||
val openUrl: String? = null,
|
||||
val isDisclaimerAccepted: Boolean = false,
|
||||
val shareTransition: FragmentShareTransition? = null,
|
||||
val btnScanState: IndeterminateProgressButton = IndeterminateProgressButton(ButtonState.ENABLED),
|
||||
val dialog: StateDialog? = null,
|
||||
) : StateType
|
||||
|
||||
sealed class HomeDialog: StateDialog {
|
||||
object ScanFailsDialog: HomeDialog()
|
||||
sealed class HomeDialog : StateDialog {
|
||||
object ScanFailsDialog : HomeDialog()
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
package com.tangem.tap.features.onboarding
|
||||
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.domain.TapWalletManager
|
||||
import com.tangem.tap.domain.TapWorkarounds.isTangemNote
|
||||
import com.tangem.tap.domain.TapWorkarounds.isTangemWallet
|
||||
import com.tangem.tap.domain.UrlBitmapLoader
|
||||
import com.tangem.tap.domain.extensions.getArtworkUrl
|
||||
import com.tangem.tap.domain.extensions.hasWallets
|
||||
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.domain.twins.isTangemTwin
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingData
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import com.tangem.tap.persistence.UsedCardsPrefStorage
|
||||
import com.tangem.tap.store
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class OnboardingService(
|
||||
private val tapWalletManager: TapWalletManager,
|
||||
private val cardInfoStorage: UsedCardsPrefStorage
|
||||
) {
|
||||
|
||||
var onReadyToProceed: ((OnboardingData) -> Unit)? = null
|
||||
set(value) {
|
||||
field = value
|
||||
onboardingDataLinker.onReady = { value?.invoke(it) }
|
||||
}
|
||||
var onFailedToProceedToOnboardingCase: (suspend (ScanNoteResponse) -> Unit)? = null
|
||||
var onError: ((String) -> Unit)? = null
|
||||
|
||||
private val onboardingDataLinker = OnboardingDataLinker()
|
||||
|
||||
suspend fun onSuccess(response: ScanNoteResponse) {
|
||||
onboardingDataLinker.scanNoteResponse = response
|
||||
val card = response.card
|
||||
val hasWallets = card.hasWallets()
|
||||
|
||||
if (!card.isTangemNote() && !card.isTangemWallet() && !card.isTangemTwin()) {
|
||||
if (hasWallets) {
|
||||
cardInfoStorage.activated(card.cardId)
|
||||
onFailedToProceedToOnboardingCase?.invoke(response)
|
||||
return
|
||||
} else {
|
||||
cardInfoStorage.activated(card.cardId) // вызвать только после того, как был создан кошелек
|
||||
onboardingDataLinker.navigateTo = AppScreen.OnboardingOther
|
||||
}
|
||||
}
|
||||
if (cardInfoStorage.wasActivated(card.cardId)) {
|
||||
onFailedToProceedToOnboardingCase?.invoke(response)
|
||||
return
|
||||
}
|
||||
|
||||
loadCardImage(card) { onboardingDataLinker.cardArtwork = it }
|
||||
|
||||
if (hasWallets) {
|
||||
val walletManagerFactory = tapWalletManager.walletManagerFactory
|
||||
when {
|
||||
card.isTangemNote() -> loadBalanceNote(walletManagerFactory, response)
|
||||
card.isTangemWallet() -> loadBalanceWallet(walletManagerFactory, response)
|
||||
card.isTangemTwin() -> loadBalanceTwins(walletManagerFactory, response)
|
||||
}
|
||||
} else {
|
||||
onboardingDataLinker.valueOfWalletAmount = BigDecimal.ZERO
|
||||
}
|
||||
|
||||
onboardingDataLinker.navigateTo = when {
|
||||
card.isTangemNote() -> AppScreen.OnboardingNote
|
||||
card.isTangemWallet() -> AppScreen.OnboardingWallet
|
||||
card.isTangemTwin() -> AppScreen.OnboardingTwins
|
||||
else -> AppScreen.OnboardingOther
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadBalanceNote(walletManagerFactory: WalletManagerFactory, response: ScanNoteResponse) {
|
||||
val walletManager: WalletManager = walletManagerFactory.makePrimaryWalletManager(response).guard {
|
||||
onError?.invoke("Can't proceed: primary wallet manager didn't create")
|
||||
return
|
||||
}
|
||||
walletManager.update()
|
||||
store.dispatch(OnboardingNoteAction.SetWalletManager(walletManager))
|
||||
|
||||
val wallet = walletManager.wallet
|
||||
val valueOfAmount = wallet.amounts[AmountType.Coin]?.value
|
||||
if (valueOfAmount == null) {
|
||||
onError?.invoke("Amount can't be NULL")
|
||||
return
|
||||
}
|
||||
|
||||
onboardingDataLinker.valueOfWalletAmount = valueOfAmount
|
||||
}
|
||||
|
||||
private suspend fun loadBalanceWallet(walletManagerFactory: WalletManagerFactory, response: ScanNoteResponse) {
|
||||
|
||||
}
|
||||
|
||||
private suspend fun loadBalanceTwins(walletManagerFactory: WalletManagerFactory, response: ScanNoteResponse) {
|
||||
|
||||
}
|
||||
|
||||
private suspend fun loadCardImage(card: Card, callback: (Artwork?) -> Unit) {
|
||||
fun loadBitmap(url: String, callback: (Artwork?) -> Unit) {
|
||||
UrlBitmapLoader().loadBitmap(url) {
|
||||
when (it) {
|
||||
is Result.Success -> callback(Artwork(url, it.data))
|
||||
is Result.Failure -> callback(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (val cardInfoResult = OnlineCardVerifier().getCardInfo(card.cardId, card.cardPublicKey)) {
|
||||
is Result.Success -> {
|
||||
val artworkUrl = card.getArtworkUrl(cardInfoResult.data.artwork?.id) ?: Artwork.DEFAULT_IMG_URL
|
||||
loadBitmap(artworkUrl, callback)
|
||||
}
|
||||
is Result.Failure -> loadBitmap(Artwork.DEFAULT_IMG_URL, callback)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class OnboardingDataLinker {
|
||||
var onReady: ((OnboardingData) -> Unit)? = null
|
||||
|
||||
internal var scanNoteResponse: ScanNoteResponse? = null
|
||||
set(value) {
|
||||
field = value
|
||||
tryToProceed()
|
||||
}
|
||||
internal var cardArtwork: Artwork? = null
|
||||
set(value) {
|
||||
field = value
|
||||
tryToProceed()
|
||||
}
|
||||
internal var valueOfWalletAmount: BigDecimal? = null
|
||||
set(value) {
|
||||
field = value
|
||||
tryToProceed()
|
||||
}
|
||||
internal var navigateTo: AppScreen? = null
|
||||
set(value) {
|
||||
field = value
|
||||
tryToProceed()
|
||||
}
|
||||
|
||||
private fun tryToProceed() {
|
||||
if (!isReady()) return
|
||||
|
||||
val data = OnboardingData(scanNoteResponse!!, cardArtwork!!, valueOfWalletAmount, navigateTo!!)
|
||||
onReady?.invoke(data)
|
||||
}
|
||||
|
||||
private fun isReady(): Boolean {
|
||||
val objList = mutableListOf(scanNoteResponse, cardArtwork, valueOfWalletAmount, navigateTo)
|
||||
return !objList.any { it == null }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package com.tangem.tap.features.onboarding.products.note
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.common.extensions.addOnBackPressedDispatcher
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction
|
||||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteState
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingAction
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingNoteStep
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding.*
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class OnboardingNoteFragment : BaseStoreFragment(R.layout.fragment_onboarding), StoreSubscriber<OnboardingNoteState> {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
activity?.addOnBackPressedDispatcher {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatch(OnboardingAction.SetInitialStepOfScreen(OnboardingNoteStep.None))
|
||||
}
|
||||
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
store.dispatch(OnboardingNoteAction.Init)
|
||||
|
||||
imv_front_card.setImageBitmap(store.state.onboardingState.onboardingData?.cardArtwork?.artwork)
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.onboardingNoteState == newState.onboardingNoteState
|
||||
}.select { it.onboardingNoteState }
|
||||
}
|
||||
}
|
||||
|
||||
override fun newState(state: OnboardingNoteState) {
|
||||
if (activity == null) return
|
||||
|
||||
pb_state.max = state.steps.size - 1
|
||||
|
||||
onboarding_main_container.beginDelayedTransition()
|
||||
when (state.currentStep) {
|
||||
OnboardingNoteStep.None -> setupNoneState(state)
|
||||
OnboardingNoteStep.CreateWallet -> setupCreateWalletState(state)
|
||||
OnboardingNoteStep.TopUpWallet -> setupTopUpWalletState(state)
|
||||
OnboardingNoteStep.Done -> setupSuccessState(state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupNoneState(state: OnboardingNoteState) {
|
||||
pb_state.progress = state.progress
|
||||
|
||||
btn_main_action.isVisible = true
|
||||
btn_alternative_action.isVisible = true
|
||||
btn_check_balance.isVisible = true
|
||||
tv_header.isVisible = true
|
||||
tv_body.isVisible = true
|
||||
|
||||
btn_main_action.text = "NULL"
|
||||
btn_alternative_action.text = "NULL"
|
||||
btn_check_balance.text = "NULL balance"
|
||||
tv_header.text = "NULL"
|
||||
tv_body.text = "NULL"
|
||||
}
|
||||
|
||||
private fun setupCreateWalletState(state: OnboardingNoteState) {
|
||||
pb_state.progress = state.progress
|
||||
|
||||
btn_main_action.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
btn_main_action.setOnClickListener { store.dispatch(OnboardingNoteAction.CreateWallet) }
|
||||
|
||||
btn_alternative_action.setText(R.string.onboarding_button_what_does_it_mean)
|
||||
btn_alternative_action.setOnClickListener { }
|
||||
|
||||
btn_check_balance.isVisible = false
|
||||
btn_check_balance.setOnClickListener { }
|
||||
|
||||
tv_header.setText(R.string.onboarding_create_wallet_header)
|
||||
tv_body.setText(R.string.onboarding_create_wallet_body)
|
||||
}
|
||||
|
||||
private fun setupTopUpWalletState(state: OnboardingNoteState) {
|
||||
pb_state.progress = state.progress
|
||||
|
||||
btn_main_action.setText(R.string.onboarding_top_up_button_but_crypto)
|
||||
btn_main_action.setOnClickListener { store.dispatch(OnboardingNoteAction.TopUp) }
|
||||
|
||||
btn_alternative_action.setText(R.string.onboarding_top_up_button_show_wallet_address)
|
||||
btn_alternative_action.setOnClickListener { }
|
||||
|
||||
btn_check_balance.isVisible = false
|
||||
btn_check_balance.setOnClickListener { }
|
||||
|
||||
tv_header.setText(R.string.onboarding_top_up_header)
|
||||
tv_body.setText(R.string.onboarding_top_up_body)
|
||||
}
|
||||
|
||||
private fun setupSuccessState(state: OnboardingNoteState) {
|
||||
pb_state.progress = state.progress
|
||||
|
||||
btn_main_action.setText(R.string.onboarding_done_button_continue)
|
||||
btn_main_action.setOnClickListener { store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) }
|
||||
|
||||
btn_alternative_action.isVisible = false
|
||||
btn_alternative_action.setText("")
|
||||
btn_alternative_action.setOnClickListener { }
|
||||
|
||||
btn_check_balance.isVisible = false
|
||||
btn_check_balance.setOnClickListener { }
|
||||
|
||||
tv_header.setText(R.string.onboarding_done_header)
|
||||
tv_body.setText(R.string.onboarding_done_body)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.tap.features.onboarding.products.note.redux
|
||||
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import org.rekotlin.Action
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class OnboardingNoteAction : Action {
|
||||
object Init : OnboardingNoteAction()
|
||||
object CreateWallet : OnboardingNoteAction()
|
||||
object TopUp : OnboardingNoteAction()
|
||||
object Done : OnboardingNoteAction()
|
||||
|
||||
data class SetWalletManager(val walletManager: WalletManager) : OnboardingNoteAction()
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.tangem.tap.features.onboarding.products.note.redux
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingAction
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingNoteStep
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class OnboardingNoteMiddleware {
|
||||
companion object {
|
||||
private const val CARD_SHOP_URI =
|
||||
"https://shop.tangem.com/?afmc=1i&utm_campaign=1i&utm_source=leaddyno&utm_medium=affiliate"
|
||||
val handler = onboardingNoteMiddleware
|
||||
}
|
||||
}
|
||||
|
||||
private val onboardingNoteMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
handleMainOnboardingAction(action, ::handleNoteAction)
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMainOnboardingAction(action: Action, isNotMainAction: (Action) -> Unit) {
|
||||
val action = action as? OnboardingAction ?: isNotMainAction(action)
|
||||
|
||||
when (action) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNoteAction(action: Action) {
|
||||
val onboardingState = store.state.onboardingState
|
||||
val noteState = store.state.onboardingNoteState
|
||||
|
||||
when (action) {
|
||||
is OnboardingNoteAction.SetWalletManager -> {
|
||||
}
|
||||
is OnboardingNoteAction.Init -> {
|
||||
val step = if (noteState.walletManager == null) {
|
||||
OnboardingNoteStep.CreateWallet
|
||||
} else {
|
||||
OnboardingNoteStep.TopUpWallet
|
||||
}
|
||||
store.dispatch(OnboardingAction.SetInitialStepOfScreen(step))
|
||||
}
|
||||
is OnboardingNoteAction.CreateWallet -> {
|
||||
scope.launch {
|
||||
val scanNoteResponse = onboardingState.onboardingData?.scanNoteResponse
|
||||
val result = tangemSdkManager.createWallet(scanNoteResponse?.card?.cardId)
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
// val scanNoteResponse = scanNoteResponse!!.copy(card = result.data)
|
||||
// store.dispatch(OnboardingAction.SetScanNoteResponse(scanNoteResponse))
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
store.dispatch(OnboardingAction.Error("Failed to create wallet"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is OnboardingNoteAction.TopUp -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.tap.features.onboarding.products.note.redux
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingAction
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingNoteStep
|
||||
import org.rekotlin.Action
|
||||
|
||||
class OnboardingNoteReducer {
|
||||
companion object {
|
||||
fun reduce(action: Action, state: AppState): OnboardingNoteState = internalReduce(action, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, appState: AppState): OnboardingNoteState {
|
||||
var state = appState.onboardingNoteState
|
||||
|
||||
when (action) {
|
||||
is OnboardingAction.SetInitialStepOfScreen -> {
|
||||
(action.step as? OnboardingNoteStep)?.let {
|
||||
if (it != state.currentStep && state.steps.contains(it)) {
|
||||
state = state.copy(currentStep = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
OnboardingAction.SwitchToNextStep -> {
|
||||
val progress = state.progress
|
||||
if (progress >= 0 && progress != state.steps.size - 1) {
|
||||
state = state.copy(currentStep = state.steps[progress + 1])
|
||||
}
|
||||
}
|
||||
is OnboardingNoteAction.SetWalletManager -> {
|
||||
state = state.copy(walletManager = action.walletManager)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.features.onboarding.products.note.redux
|
||||
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingNoteStep
|
||||
import org.rekotlin.StateType
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class OnboardingNoteState(
|
||||
val walletManager: WalletManager? = null,
|
||||
val currentStep: OnboardingNoteStep = OnboardingNoteStep.None,
|
||||
val steps: List<OnboardingNoteStep> = OnboardingNoteStep.values().toList(),
|
||||
) : StateType {
|
||||
|
||||
val progress: Int
|
||||
get() = steps.indexOf(currentStep)
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.tap.features.onboarding.products.old
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.common.extensions.addOnBackPressedDispatcher
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingAction
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingOtherCardsState
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingOtherStep
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class OnboardingOtherCardsFragment : BaseStoreFragment(R.layout.fragment_onboarding), StoreSubscriber<OnboardingOtherCardsState> {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
activity?.addOnBackPressedDispatcher {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatch(OnboardingAction.SetInitialStepOfScreen(OnboardingOtherStep.Done))
|
||||
}
|
||||
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
// store.subscribe(this) { state ->
|
||||
// state.skipRepeats { oldState, newState ->
|
||||
// oldState.onboardingOtherState == newState.onboardingOtherState
|
||||
// }.select { it.onboardingOtherState }
|
||||
// }
|
||||
}
|
||||
|
||||
override fun newState(state: OnboardingOtherCardsState) {
|
||||
if (activity == null) return
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.common.extensions.addOnBackPressedDispatcher
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingAction
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingOtherStep
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class OnboardingWalletFragment : BaseStoreFragment(R.layout.fragment_onboarding_wallet), StoreSubscriber<OnboardingWalletState> {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
activity?.addOnBackPressedDispatcher {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatch(OnboardingAction.SetInitialStepOfScreen(OnboardingOtherStep.Done))
|
||||
}
|
||||
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
store.dispatch(OnboardingAction.OnboardingOtherAction.Init)
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.onboardingWalletState == newState.onboardingWalletState
|
||||
}.select { it.onboardingWalletState }
|
||||
}
|
||||
}
|
||||
|
||||
override fun newState(state: OnboardingWalletState) {
|
||||
if (activity == null) return
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import org.rekotlin.Action
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class OnboardingWalletAction : Action {
|
||||
object Init : OnboardingWalletAction()
|
||||
object CreateWallet : OnboardingWalletAction()
|
||||
object TopUp : OnboardingWalletAction()
|
||||
object Done : OnboardingWalletAction()
|
||||
|
||||
object ProceedBackup : OnboardingWalletAction()
|
||||
|
||||
sealed class Backup : Action {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class OnboardingWalletMiddleware {
|
||||
companion object {
|
||||
val handler = onboardingWalletMiddleware
|
||||
}
|
||||
}
|
||||
|
||||
private val onboardingWalletMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import org.rekotlin.Action
|
||||
|
||||
class OnboardingWalletReducer {
|
||||
companion object {
|
||||
fun reduce(action: Action, state: AppState): OnboardingWalletState = internalReduce(action, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, appState: AppState): OnboardingWalletState {
|
||||
var state = appState.onboardingWalletState
|
||||
|
||||
when (action) {
|
||||
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import com.tangem.tap.features.onboarding.redux.OnboardingStep
|
||||
import org.rekotlin.StateType
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class OnboardingWalletState(
|
||||
val any: String? = null
|
||||
) : StateType
|
||||
|
||||
enum class OnboardingWalletStep : OnboardingStep {
|
||||
None, CreateWallet, TopUpWallet, Backup, Done
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.tap.features.onboarding.redux
|
||||
|
||||
import org.rekotlin.Action
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class OnboardingAction : Action {
|
||||
|
||||
data class SetInitialStepOfScreen(val step: OnboardingStep) : OnboardingAction()
|
||||
object SwitchToNextStep : OnboardingAction()
|
||||
|
||||
data class SetData(val data: OnboardingData) : OnboardingAction()
|
||||
|
||||
sealed class OnboardingOtherAction : Action {
|
||||
object Init : OnboardingOtherAction()
|
||||
object CreateWallet : OnboardingOtherAction()
|
||||
object Done : OnboardingOtherAction()
|
||||
}
|
||||
|
||||
class Error(val message: String) : OnboardingAction()
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.tap.features.onboarding.redux
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class OnboardingMiddleware {
|
||||
companion object {
|
||||
val handler = onboardingMiddleware
|
||||
}
|
||||
}
|
||||
|
||||
private val onboardingMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
val onboardingState = store.state.onboardingState
|
||||
when (action) {
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.tap.features.onboarding.redux
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import org.rekotlin.Action
|
||||
|
||||
class OnboardingReducer {
|
||||
companion object {
|
||||
fun reduce(action: Action, state: AppState): OnboardingState = internalReduce(action, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, appState: AppState): OnboardingState {
|
||||
|
||||
if (action !is OnboardingAction) return appState.onboardingState
|
||||
|
||||
var state = appState.onboardingState
|
||||
when (action) {
|
||||
is OnboardingAction.SetData -> {
|
||||
state = state.copy(onboardingData = action.data)
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.tap.features.onboarding.redux
|
||||
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class OnboardingState(
|
||||
val onboardingData: OnboardingData? = null,
|
||||
) : StateType
|
||||
|
||||
data class OnboardingOtherCardsState(
|
||||
val any: String? = null
|
||||
) : StateType
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.tap.features.onboarding.redux
|
||||
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class OnboardingData(
|
||||
val scanNoteResponse: ScanNoteResponse,
|
||||
val cardArtwork: Artwork,
|
||||
val balance: BigDecimal?,
|
||||
val onboardingScreen: AppScreen
|
||||
)
|
||||
|
||||
interface OnboardingStep
|
||||
|
||||
enum class OnboardingNoteStep : OnboardingStep {
|
||||
None, CreateWallet, TopUpWallet, Done
|
||||
}
|
||||
|
||||
enum class OnboardingOtherStep : OnboardingStep {
|
||||
CreateWallet, Done
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ import com.tangem.wallet.R
|
|||
import kotlinx.android.synthetic.main.fragment_twin_cards.*
|
||||
import kotlinx.android.synthetic.main.layout_twin_cards.*
|
||||
|
||||
class TwinsOnboardingFragment : Fragment(R.layout.fragment_twin_cards) {
|
||||
class OnboardingTwinsFragment : Fragment(R.layout.fragment_twin_cards) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -107,7 +107,7 @@ class SingleWalletView : WalletView {
|
|||
tv_twin_card_number.hide()
|
||||
}
|
||||
if (twinCardsState?.showTwinOnboarding == true) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding))
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue