From e080401183ed510a498488ea0e535d4415e8f9ec Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 13:04:54 +0300 Subject: [PATCH] Updated on 2026-08-14 --- app/build.gradle.kts | 1 - .../main/java/com/tangem/tap/MainActivity.kt | 16 +- .../com/tangem/tap/common/DialogManager.kt | 15 +- .../com/tangem/tap/common/redux/AppReducer.kt | 8 - .../com/tangem/tap/common/redux/AppState.kt | 16 - .../tap/common/redux/global/GlobalAction.kt | 24 - .../tap/common/redux/global/GlobalReducer.kt | 16 - .../common/redux/legacy/LegacyMiddleware.kt | 11 - .../tangem/tap/di/domain/MnemonicModule.kt | 24 - .../com/tangem/tap/domain/TapWalletManager.kt | 2 - .../domain/scanCard/LegacyScanProcessor.kt | 38 +- .../chains/CheckForOnboardingChain.kt | 42 +- .../tangem/tap/features/demo/DemoHelper.kt | 10 - .../demo/DemoOnboardingNoteMiddleware.kt | 65 - .../cardsettings/model/CardSettingsModel.kt | 28 +- .../tangem/tap/features/main/MainViewModel.kt | 12 + .../features/onboarding/OnboardingDialog.kt | 3 - .../features/onboarding/OnboardingHelper.kt | 242 +- .../features/onboarding/OnboardingManager.kt | 137 +- .../onboarding/OnboardingMenuProvider.kt | 47 - .../products/BaseOnboardingFragment.kt | 54 - .../products/note/OnboardingNoteFragment.kt | 228 -- .../note/redux/OnboardingNoteAction.kt | 39 - .../note/redux/OnboardingNoteMiddleware.kt | 197 -- .../note/redux/OnboardingNoteReducer.kt | 47 - .../note/redux/OnboardingNoteState.kt | 31 - .../OnboardingOtherCardsFragment.kt | 128 -- .../redux/OnboardingOtherCardsAction.kt | 26 - .../redux/OnboardingOtherCardsMiddleware.kt | 129 -- .../redux/OnboardingOtherCardsReducer.kt | 35 - .../redux/OnboardingOtherCardsState.kt | 22 - .../products/twins/redux/TwinCardsAction.kt | 66 - .../twins/redux/TwinCardsMiddleware.kt | 399 ---- .../products/twins/redux/TwinCardsReducer.kt | 77 - .../products/twins/redux/TwinCardsState.kt | 82 - .../twins/ui/OnboardingTwinsFragment.kt | 460 ---- .../TwinningProcessNotCompletedDialog.kt | 21 - .../products/wallet/redux/BackupDialog.kt | 14 + .../products/wallet/redux/BackupMiddleware.kt | 59 + .../wallet/redux/OnboardingWalletAction.kt | 89 - .../redux/OnboardingWalletMiddleware.kt | 849 ------- .../wallet/redux/OnboardingWalletReducer.kt | 185 -- .../wallet/redux/OnboardingWalletState.kt | 128 -- .../products/wallet/ui/BackupAnimator.kt | 314 --- .../products/wallet/ui/BackupInfoAdapter.kt | 57 - .../ui/OnboardingSeedPhraseStateHandler.kt | 82 - .../wallet/ui/OnboardingWalletFragment.kt | 691 ------ .../products/wallet/ui/WalletCardsWidget.kt | 240 -- .../wallet/ui/dialogs/AccessCodeDialog.kt | 81 - .../ui/dialogs/AddMoreBackupCardsDialog.kt | 26 - .../ui/dialogs/AttestationFailedDialog.kt | 24 - .../ui/dialogs/BackupInProgressDialog.kt | 23 - .../ui/dialogs/InterruptOnboardingDialog.kt | 25 - .../ui/dialogs/ResetBackupCardDialog.kt | 30 - .../tangem/tap/routing/utils/ChildFactory.kt | 20 - .../com/tangem/common/routing/AppRoute.kt | 21 - .../configs/feature_toggles_config.json | 12 - .../com/tangem/domain/redux/LegacyAction.kt | 8 - .../v2/OnboardingV2FeatureToggles.kt | 3 - .../v2/DefaultOnboardingV2FeatureToggles.kt | 6 - features/onboarding/.gitignore | 1 - features/onboarding/build.gradle.kts | 64 - .../mnemonic/mnemonic_dictionary_en.txt | 2048 ----------------- .../onboarding/api/OnboardingSeedPhraseApi.kt | 14 - .../api/OnboardingSeedPhraseScreen.kt | 71 - .../data/DefaultMnemonicRepository.kt | 32 - .../onboarding/data/MnemonicRepository.kt | 22 - .../data/model/CreateWalletResponse.kt | 15 - .../onboarding/di/OnboardingRouterModule.kt | 20 - .../domain/DefaultSeedPhraseInteractor.kt | 113 - .../domain/OnboardingModuleError.kt | 41 - .../onboarding/domain/PartWordFinder.kt | 50 - .../onboarding/domain/SeedPhraseInteractor.kt | 27 - .../domain/di/OnboardingDomainModule.kt | 21 - .../onboarding/domain/models/MnemonicType.kt | 5 - .../navigation/DefaultOnboardingRouter.kt | 3 - .../onboarding/navigation/OnboardingRouter.kt | 7 - .../wallet2/analytics/SeedPhraseEvents.kt | 41 - .../presentation/wallet2/model/ButtonState.kt | 11 - .../wallet2/model/DescriptionResource.kt | 8 - .../model/OnboardingSeedPhraseState.kt | 102 - .../presentation/wallet2/model/UiActions.kt | 60 - .../wallet2/ui/AboutSeedPhraseScreen.kt | 151 -- .../wallet2/ui/CheckSeedPhraseScreen.kt | 110 - .../wallet2/ui/ImportSeedPhraseScreen.kt | 268 --- .../presentation/wallet2/ui/IntroScreen.kt | 102 - .../wallet2/ui/PassphraseInfoBottomSheet.kt | 90 - .../wallet2/ui/YourSeedPhraseScreen.kt | 196 -- .../ui/components/OnboardingActionBlock.kt | 39 - .../components/OnboardingDescriptionBlock.kt | 64 - .../CheckSeedPhraseStateBuilder.kt | 77 - .../ImportSeedPhraseStateBuilder.kt | 108 - .../wallet2/ui/stateBuiders/StateBuilder.kt | 197 -- .../InvalidWordsColorTransformation.kt | 79 - .../viewmodel/SeedPhraseErrorConverter.kt | 28 - .../wallet2/viewmodel/SeedPhraseMediator.kt | 22 - .../wallet2/viewmodel/SeedPhraseRouter.kt | 50 - .../wallet2/viewmodel/SeedPhraseViewModel.kt | 484 ---- .../model/WalletSettingsModel.kt | 28 +- features/wallet/impl/build.gradle.kts | 3 - .../intents/WalletWarningsClickIntents.kt | 11 - .../router/DefaultWalletRouter.kt | 28 +- settings.gradle.kts | 1 - 103 files changed, 142 insertions(+), 10555 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/TwinningProcessNotCompletedDialog.kt create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupDialog.kt create mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingSeedPhraseStateHandler.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AccessCodeDialog.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AddMoreBackupCardsDialog.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AttestationFailedDialog.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/BackupInProgressDialog.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/InterruptOnboardingDialog.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/ResetBackupCardDialog.kt delete mode 100644 features/onboarding/.gitignore delete mode 100644 features/onboarding/build.gradle.kts delete mode 100644 features/onboarding/src/main/assets/mnemonic/mnemonic_dictionary_en.txt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseApi.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/data/MnemonicRepository.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/data/model/CreateWalletResponse.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/di/OnboardingRouterModule.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/DefaultSeedPhraseInteractor.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/OnboardingModuleError.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/PartWordFinder.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/SeedPhraseInteractor.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/di/OnboardingDomainModule.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/models/MnemonicType.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/DefaultOnboardingRouter.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/OnboardingRouter.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/analytics/SeedPhraseEvents.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/ButtonState.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/DescriptionResource.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/OnboardingSeedPhraseState.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/UiActions.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/CheckSeedPhraseScreen.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/IntroScreen.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingActionBlock.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/CheckSeedPhraseStateBuilder.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/ImportSeedPhraseStateBuilder.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/StateBuilder.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/InvalidWordsColorTransformation.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseErrorConverter.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseMediator.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseRouter.kt delete mode 100644 features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7d7888942f..154659cd53 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -158,7 +158,6 @@ dependencies { implementation(projects.data.blockaid) /** Features */ - implementation(projects.features.onboarding) implementation(projects.features.referral.impl) implementation(projects.features.referral.domain) implementation(projects.features.referral.data) diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 3eb6102ce8..081728b21c 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -62,13 +62,11 @@ import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent -import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.google.GoogleServicesHelper import com.tangem.operations.backup.BackupService import com.tangem.sdk.api.BackupServiceHolder import com.tangem.sdk.api.TangemSdkManager -import com.tangem.sdk.extensions.init import com.tangem.tap.common.ActivityResultCallbackHolder import com.tangem.tap.common.DialogManager import com.tangem.tap.common.OnActivityResultCallback @@ -83,7 +81,6 @@ import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandle import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler import com.tangem.tap.features.main.MainViewModel -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.proxy.redux.DaggerGraphAction import com.tangem.tap.routing.component.RoutingComponent @@ -181,9 +178,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var backupServiceHolder: BackupServiceHolder - @Inject - lateinit var onboardingV2FeatureToggles: OnboardingV2FeatureToggles - @Inject lateinit var setGoogleServicesAvailabilityUseCase: SetGoogleServicesAvailabilityUseCase @@ -364,12 +358,8 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac cardSdkOwner.register(activity = this) tangemSdkManager = injectedTangemSdkManager - if (onboardingV2FeatureToggles.isOnboardingV2Enabled) { - backupServiceHolder.createAndSetService(cardSdkConfigRepository.sdk, this) - backupService = backupServiceHolder.backupService.get()!! // will be deleted eventually - } else { - backupService = BackupService.init(cardSdkConfigRepository.sdk, this) - } + backupServiceHolder.createAndSetService(cardSdkConfigRepository.sdk, this) + backupService = backupServiceHolder.backupService.get()!! // will be deleted eventually lockUserWalletsTimer = LockUserWalletsTimer( context = this, @@ -662,7 +652,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac } } - store.dispatch(BackupAction.CheckForUnfinishedBackup) + viewModel.checkForUnfinishedBackup() } private fun observePolkadotAccountHealthCheck() { diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index 533cdac6a9..d60fbd6473 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -9,9 +9,11 @@ import com.tangem.tap.common.ui.* import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog import com.tangem.tap.features.details.ui.walletconnect.dialogs.* import com.tangem.tap.features.onboarding.OnboardingDialog -import com.tangem.tap.features.onboarding.products.twins.ui.dialog.TwinningProcessNotCompletedDialog import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog -import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.* +import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.ConfirmDiscardingBackupDialog +import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.UnfinishedBackupFoundDialog +import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.WalletActivationErrorDialog +import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.WalletAlreadyWasUsedDialog import com.tangem.tap.store import com.tangem.wallet.R import org.rekotlin.StoreSubscriber @@ -58,8 +60,6 @@ class DialogManager : StoreSubscriber { ) is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context) is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context) - is OnboardingDialog.TwinningProcessNotCompleted -> TwinningProcessNotCompletedDialog.create(context) - is OnboardingDialog.InterruptOnboarding -> InterruptOnboardingDialog.create(context, state.dialog) is OnboardingDialog.WalletActivationError -> WalletActivationErrorDialog.create(context, state.dialog) is WalletConnectDialog.UnsupportedCard -> SimpleAlertDialog.create( @@ -143,9 +143,6 @@ class DialogManager : StoreSubscriber { messageRes = R.string.unsupported_wc_version, context = context, ) - is BackupDialog.AttestationFailed -> AttestationFailedDialog.create(context) - is BackupDialog.AddMoreBackupCards -> AddMoreBackupCardsDialog.create(context) - is BackupDialog.BackupInProgress -> BackupInProgressDialog.create(context) is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create( context = context, scanResponse = state.dialog.scanResponse, @@ -154,10 +151,6 @@ class DialogManager : StoreSubscriber { context = context, unfinishedBackupScanResponse = state.dialog.scanResponse, ) - is BackupDialog.ResetBackupCard -> ResetBackupCardDialog.create( - context = context, - cardId = state.dialog.cardId, - ) is AppDialog.TokensAreLinkedDialog -> SimpleAlertDialog.create( title = context.getString(state.dialog.titleRes, state.dialog.currencySymbol), message = context.getString( diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index 80b48b4193..7aa2d7a120 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -4,10 +4,6 @@ import com.tangem.tap.common.redux.global.globalReducer import com.tangem.tap.features.details.redux.DetailsReducer import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer 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.otherCards.redux.OnboardingOtherCardsReducer -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsReducer -import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletReducer import com.tangem.tap.features.saveWallet.redux.SaveWalletReducer import com.tangem.tap.features.welcome.redux.WelcomeReducer import com.tangem.tap.proxy.redux.DaggerGraphReducer @@ -20,10 +16,6 @@ fun appReducer(action: Action, state: AppState?): AppState { return AppState( globalState = globalReducer(action, state), homeState = HomeReducer.reduce(action, state), - onboardingNoteState = OnboardingNoteReducer.reduce(action, state), - onboardingWalletState = OnboardingWalletReducer.reduce(action, state), - onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state), - twinCardsState = TwinCardsReducer.reduce(action, state), detailsState = DetailsReducer.reduce(action, state), walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState), welcomeState = WelcomeReducer.reduce(action, state), diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 04d6fa4896..99946cc324 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -9,15 +9,7 @@ import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddlewa import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState 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.otherCards.redux.OnboardingOtherCardsMiddleware -import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsState -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsMiddleware -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.onboarding.products.wallet.redux.BackupMiddleware -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.saveWallet.redux.SaveWalletMiddleware import com.tangem.tap.features.saveWallet.redux.SaveWalletState import com.tangem.tap.features.wallet.redux.middlewares.TradeCryptoMiddleware @@ -31,10 +23,6 @@ import org.rekotlin.StateType data class AppState( val globalState: GlobalState = GlobalState(), val homeState: HomeState = HomeState(), - val onboardingNoteState: OnboardingNoteState = OnboardingNoteState(), - val onboardingWalletState: OnboardingWalletState = OnboardingWalletState(), - val onboardingOtherCardsState: OnboardingOtherCardsState = OnboardingOtherCardsState(), - val twinCardsState: TwinCardsState = TwinCardsState(), val detailsState: DetailsState = DetailsState(), val walletConnectState: WalletConnectState = WalletConnectState(), val welcomeState: WelcomeState = WelcomeState(), @@ -49,10 +37,6 @@ data class AppState( notificationsMiddleware, GlobalMiddleware.handler, HomeMiddleware.handler, - OnboardingNoteMiddleware.handler, - OnboardingWalletMiddleware.handler, - OnboardingOtherCardsMiddleware.handler, - TwinCardsMiddleware.handler, DetailsMiddleware().detailsMiddleware, WalletConnectMiddleware().walletConnectMiddleware, BackupMiddleware().backupMiddleware, diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt index 1c984ff096..79947dc0ac 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt @@ -8,7 +8,6 @@ import com.tangem.domain.redux.StateDialog import com.tangem.tap.common.redux.DebugErrorAction import com.tangem.tap.common.redux.ErrorAction import com.tangem.tap.domain.TapError -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource import org.rekotlin.Action sealed class GlobalAction : Action { @@ -21,29 +20,6 @@ sealed class GlobalAction : Action { data class ShowDialog(val stateDialog: StateDialog) : GlobalAction() object HideDialog : GlobalAction() - sealed class Onboarding : GlobalAction() { - /** - * Initiate an onboarding process. - * For resuming unfinished backup of standard Wallet see - * BackupAction.CheckForUnfinishedBackup, GlobalAction.Onboarding.StartForUnfinishedBackup - */ - data class Start( - val scanResponse: ScanResponse, - val source: BackupStartedSource, - val canSkipBackup: Boolean = true, - ) : Onboarding() - - /** - * Initiate resuming of unfinished backup for standard Wallet. - * See more BackupAction.CheckForUnfinishedBackup - */ - data class StartForUnfinishedBackup(val addedBackupCardsCount: Int) : Onboarding() - - object Stop : Onboarding() - - data class ShouldResetCardOnCreate(val shouldReset: Boolean) : Onboarding() - } - object ScanFailsCounter { data class ChooseBehavior( val result: CompletionResult, diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index c8372a3d0d..51da092058 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -1,7 +1,6 @@ package com.tangem.tap.common.redux.global import com.tangem.tap.common.redux.AppState -import com.tangem.tap.features.onboarding.OnboardingManager import com.tangem.utils.extensions.replaceBy import org.rekotlin.Action @@ -12,21 +11,6 @@ fun globalReducer(action: Action, state: AppState): GlobalState { val globalState = state.globalState return when (action) { - is GlobalAction.Onboarding.Start -> { - val onboardingManager = OnboardingManager(action.scanResponse) - globalState.copy(onboardingState = OnboardingState(true, onboardingManager)) - } - is GlobalAction.Onboarding.StartForUnfinishedBackup -> { - globalState.copy(onboardingState = OnboardingState(true, null)) - } - is GlobalAction.Onboarding.Stop -> { - globalState.copy(onboardingState = OnboardingState(false)) - } - is GlobalAction.Onboarding.ShouldResetCardOnCreate -> { - globalState.copy( - onboardingState = globalState.onboardingState.copy(shouldResetOnCreate = action.shouldReset), - ) - } is GlobalAction.ScanFailsCounter.Increment -> { globalState.copy(scanCardFailsCounter = globalState.scanCardFailsCounter + 1) } diff --git a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt index 22932d20e9..1eea5ec1a0 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt @@ -5,10 +5,8 @@ import com.tangem.domain.redux.LegacyAction import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.details.redux.AppSettingsState import com.tangem.tap.features.details.redux.DetailsAction -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store @@ -26,15 +24,6 @@ internal object LegacyMiddleware { { next -> { action -> when (action) { - is LegacyAction.StartOnboardingProcess -> { - store.dispatch( - GlobalAction.Onboarding.Start( - scanResponse = action.scanResponse, - source = BackupStartedSource.CreateBackup, - canSkipBackup = action.canSkipBackup, - ), - ) - } is LegacyAction.PrepareDetailsScreen -> { val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) val walletsRepository = store.inject(DaggerGraphState::walletsRepository) diff --git a/app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt b/app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt deleted file mode 100644 index 8f62a7e255..0000000000 --- a/app/src/main/java/com/tangem/tap/di/domain/MnemonicModule.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.tap.di.domain - -import android.content.Context -import com.tangem.crypto.bip39.Wordlist -import com.tangem.feature.onboarding.data.DefaultMnemonicRepository -import com.tangem.feature.onboarding.data.MnemonicRepository -import com.tangem.sdk.extensions.getWordlist -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -class MnemonicModule { - - @Provides - @Singleton - fun provideMnemonicRepository(@ApplicationContext context: Context): MnemonicRepository { - return DefaultMnemonicRepository(Wordlist.getWordlist(context)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 8225f9014c..63058e7738 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -7,7 +7,6 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.wallets.models.UserWallet import com.tangem.tap.common.extensions.setContext import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.store import com.tangem.tap.tangemSdkManager import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider @@ -42,7 +41,6 @@ class TapWalletManager( withMainContext { // Order is important - store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse)) store.dispatch(GlobalAction.SaveScanResponse(scanResponse)) } } diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt index 6ea8247faf..29665865af 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt @@ -21,7 +21,6 @@ import com.tangem.core.ui.message.dialog.Dialogs import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull -import com.tangem.domain.common.TapWorkarounds.canSkipBackup import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.feedback.models.FeedbackEmailType @@ -34,9 +33,6 @@ import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.disclaimer.createDisclaimer import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource import com.tangem.tap.mainScope import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope @@ -208,8 +204,6 @@ internal class LegacyScanProcessor @Inject constructor( crossinline onCancel: suspend () -> Unit, crossinline onSuccess: suspend (ScanResponse) -> Unit, ) { - store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse)) - checkCardWasUsedInApp( scanResponse = scanResponse, onCancel = { @@ -222,38 +216,26 @@ internal class LegacyScanProcessor @Inject constructor( if (OnboardingHelper.isOnboardingCase(scanResponse)) { Analytics.addContext(scanResponse) onWalletNotCreated() - // must check skip backup using card canSkipBackup - store.dispatchOnMain( - GlobalAction.Onboarding.Start( + navigateTo( + AppRoute.Onboarding( scanResponse = scanResponse, - source = BackupStartedSource.Onboarding, - canSkipBackup = scanResponse.card.canSkipBackup, + mode = AppRoute.Onboarding.Mode.Onboarding, ), - ) - val appScreen = OnboardingHelper.whereToNavigate(scanResponse) - navigateTo(appScreen) { onProgressStateChange(it) } + ) { onProgressStateChange(it) } } else { Analytics.setContext(scanResponse) - val isTwinRefactoringEnabled = - store.inject(DaggerGraphState::onboardingV2FeatureToggles).isTwinRefactoringEnabled - val wasTwinsOnboardingShown = store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase).invokeSync() if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) { onWalletNotCreated() - if (isTwinRefactoringEnabled) { - navigateTo( - AppRoute.Onboarding( - scanResponse = scanResponse, - mode = AppRoute.Onboarding.Mode.WelcomeOnlyTwin, - ), - ) { onProgressStateChange(it) } - } else { - store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse))) - navigateTo(AppRoute.OnboardingTwins) { onProgressStateChange(it) } - } + navigateTo( + AppRoute.Onboarding( + scanResponse = scanResponse, + mode = AppRoute.Onboarding.Mode.WelcomeOnlyTwin, + ), + ) { onProgressStateChange(it) } } else { delay(DELAY_SDK_DIALOG_CLOSE) onSuccess(scanResponse) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt index b9d6aff5fd..0912058b65 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt @@ -5,21 +5,15 @@ import arrow.core.right import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.Analytics import com.tangem.domain.card.ScanCardException -import com.tangem.domain.common.TapWorkarounds.canSkipBackup import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.core.chain.Chain import com.tangem.domain.core.chain.ResultChain import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.extensions.addContext -import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.extensions.setContext import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE import kotlinx.coroutines.delay @@ -40,46 +34,30 @@ class CheckForOnboardingChain( ) : ResultChain() { override suspend fun launch(previousChainResult: ScanResponse): ScanChainResult { - store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(previousChainResult)) - return when { OnboardingHelper.isOnboardingCase(previousChainResult) -> { Analytics.addContext(previousChainResult) - // must check skip backup using card canSkipBackup - store.dispatchOnMain( - GlobalAction.Onboarding.Start( + ScanChainException.OnboardingNeeded( + AppRoute.Onboarding( scanResponse = previousChainResult, - source = BackupStartedSource.Onboarding, - canSkipBackup = previousChainResult.card.canSkipBackup, + mode = AppRoute.Onboarding.Mode.Onboarding, ), - ) - val route = OnboardingHelper.whereToNavigate(previousChainResult) - ScanChainException.OnboardingNeeded(route).left() + ).left() } else -> { Analytics.setContext(previousChainResult) - val isTwinRefactoringEnabled = - store.inject(DaggerGraphState::onboardingV2FeatureToggles).isTwinRefactoringEnabled - val wasTwinsOnboardingShown = store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase) .invokeSync() // If twins was twinned previously but twins welcome not shown if (previousChainResult.twinsIsTwinned() && !wasTwinsOnboardingShown) { - if (isTwinRefactoringEnabled) { - ScanChainException.OnboardingNeeded( - AppRoute.Onboarding( - scanResponse = previousChainResult, - mode = AppRoute.Onboarding.Mode.WelcomeOnlyTwin, - ), - ).left() - } else { - store.dispatchOnMain( - TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(previousChainResult)), - ) - ScanChainException.OnboardingNeeded(AppRoute.OnboardingTwins).left() - } + ScanChainException.OnboardingNeeded( + AppRoute.Onboarding( + scanResponse = previousChainResult, + mode = AppRoute.Onboarding.Mode.WelcomeOnlyTwin, + ), + ).left() } else { delay(DELAY_SDK_DIALOG_CLOSE) previousChainResult.right() diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt index 4895cd65b9..577ac2f3a8 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt @@ -7,7 +7,6 @@ import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.redux.AppState import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store import com.tangem.wallet.R @@ -16,13 +15,8 @@ import org.rekotlin.Action object DemoHelper { val config = DemoConfig() - private val demoMiddlewares = listOf( - DemoOnboardingNoteMiddleware(), - ) - private val disabledActionFeatures = listOf( WalletConnectAction.StartWalletConnect::class.java, - BackupAction.StartBackup::class.java, ) fun isDemoCard(scanResponse: ScanResponse): Boolean = isDemoCardId(scanResponse.card.cardId) @@ -35,10 +29,6 @@ object DemoHelper { val scanResponse = getScanResponse(appState) ?: return false if (!scanResponse.isDemoCard()) return false - demoMiddlewares.forEach { - if (it.tryHandle(config, scanResponse, action)) return true - } - disabledActionFeatures.firstOrNull { it == action::class.java }?.let { val uiMessageSender = store.inject(DaggerGraphState::uiMessageSender) uiMessageSender.send( diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt deleted file mode 100644 index 4b3ac9357d..0000000000 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.tangem.tap.features.demo - -import com.tangem.common.extensions.guard -import com.tangem.domain.common.extensions.makePrimaryWalletManager -import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.demo.DemoConfig -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.common.entities.ProgressState -import com.tangem.tap.common.extensions.inject -import com.tangem.tap.domain.model.Currency -import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.scope -import com.tangem.tap.store -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.rekotlin.Action - -/** -[REDACTED_AUTHOR] - */ -internal class DemoOnboardingNoteMiddleware : DemoMiddleware { - - override fun tryHandle(config: DemoConfig, scanResponse: ScanResponse, action: Action): Boolean { - val noteState = store.state.onboardingNoteState - - return when (action) { - is OnboardingNoteAction.Balance.Update -> { - val walletManager = if (noteState.walletManager != null) { - noteState.walletManager - } else { - val wmFactory = runBlocking { - store.inject(DaggerGraphState::blockchainSDKFactory).getWalletManagerFactorySync() - } - val walletManager = wmFactory?.makePrimaryWalletManager(scanResponse).guard { - return false - } - store.dispatch(OnboardingNoteAction.SetWalletManager(walletManager)) - walletManager - } - - val balanceAmount = config.getBalance(walletManager.wallet.blockchain) - val loadedBalance = noteState.walletBalance.copy( - value = balanceAmount.value!!, - currency = Currency.Blockchain(walletManager.wallet.blockchain, null), - state = ProgressState.Done, - error = null, - criticalError = null, - ) - - walletManager.wallet.setAmount(balanceAmount) - - scope.launch { - withMainContext { - store.dispatch(OnboardingNoteAction.Balance.Set(loadedBalance)) - store.dispatch(OnboardingNoteAction.Balance.SetCriticalError(loadedBalance.criticalError)) - store.dispatch(OnboardingNoteAction.Balance.SetNonCriticalError(loadedBalance.error)) - } - } - return true - } - else -> false - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt index 894ab1be67..1390b8d0bd 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt @@ -20,7 +20,6 @@ import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.domain.wallets.usecase.GetUserWalletUseCase -import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import com.tangem.sdk.api.TangemSdkManager import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Settings @@ -33,8 +32,6 @@ import com.tangem.tap.features.details.ui.cardsettings.CardSettingsScreenState import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent import com.tangem.tap.features.details.ui.cardsettings.domain.CardSettingsInteractor import com.tangem.tap.features.details.ui.common.utils.* -import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.store import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.wallet.R @@ -56,7 +53,6 @@ internal class CardSettingsModel @Inject constructor( private val getUserWalletUseCase: GetUserWalletUseCase, private val cardSdkConfigRepository: CardSdkConfigRepository, private val settingsRepository: SettingsRepository, - private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles, ) : Model() { private val params = paramsContainer.require() @@ -200,23 +196,13 @@ internal class CardSettingsModel @Inject constructor( } if (scanResponse.cardTypesResolver.isTangemTwins()) { - if (onboardingV2FeatureToggles.isTwinRefactoringEnabled) { - store.dispatchNavigationAction { - push( - AppRoute.Onboarding( - scanResponse = scanResponse, - mode = AppRoute.Onboarding.Mode.RecreateWalletTwin, - ), - ) - } - } else { - // needs to prepare twin state if it's twin cards (depends on onboarding refactoring) - store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse)) - store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet(scanResponse))) - - cardSettingsInteractor.clear() - - store.dispatchNavigationAction { push(AppRoute.OnboardingTwins) } + store.dispatchNavigationAction { + push( + AppRoute.Onboarding( + scanResponse = scanResponse, + mode = AppRoute.Onboarding.Mode.RecreateWalletTwin, + ), + ) } } else { val card = scanResponse.card diff --git a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt index e6a4d37f48..212e39e905 100644 --- a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt @@ -21,6 +21,7 @@ import com.tangem.domain.balancehiding.BalanceHidingSettings import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.balancehiding.ListenToFlipsUseCase import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase +import com.tangem.domain.onboarding.repository.OnboardingRepository import com.tangem.domain.onramp.FetchHotCryptoUseCase import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.promo.models.StoryContentIds @@ -31,6 +32,9 @@ import com.tangem.domain.staking.FetchStakingTokensUseCase import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.feature.swap.analytics.StoriesEvents import com.tangem.tap.common.extensions.setContext +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog +import com.tangem.tap.store import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.* @@ -58,6 +62,7 @@ internal class MainViewModel @Inject constructor( private val getStoryContentUseCase: GetStoryContentUseCase, private val imagePreloader: ImagePreloader, private val fetchHotCryptoUseCase: FetchHotCryptoUseCase, + private val onboardingRepository: OnboardingRepository, getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, ) : ViewModel() { @@ -94,6 +99,13 @@ internal class MainViewModel @Inject constructor( preloadImages() } + fun checkForUnfinishedBackup() { + viewModelScope.launch(dispatchers.main) { + val onboardingScanResponse = onboardingRepository.getUnfinishedFinalizeOnboarding() ?: return@launch + store.dispatch(GlobalAction.ShowDialog(BackupDialog.UnfinishedBackupFound(onboardingScanResponse))) + } + } + /** Loading the resources needed to run the application */ private fun loadApplicationResources() { viewModelScope.launch(dispatchers.main) { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingDialog.kt index 97f17bd9b5..e2de5c257b 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingDialog.kt @@ -1,13 +1,10 @@ package com.tangem.tap.features.onboarding -import com.tangem.common.extensions.VoidCallback import com.tangem.domain.redux.StateDialog /** [REDACTED_AUTHOR] */ sealed class OnboardingDialog : StateDialog { - object TwinningProcessNotCompleted : OnboardingDialog() - data class InterruptOnboarding(val onOk: VoidCallback) : OnboardingDialog() data class WalletActivationError(val onConfirm: () -> Unit) : OnboardingDialog() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index 7eda3eb6c5..0f3997d317 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -1,46 +1,23 @@ package com.tangem.tap.features.onboarding -import com.tangem.blockchain.common.WalletManager -import com.tangem.common.doOnFailure -import com.tangem.common.doOnSuccess -import com.tangem.common.extensions.guard -import com.tangem.common.routing.AppRoute -import com.tangem.core.analytics.Analytics -import com.tangem.core.analytics.models.Basic -import com.tangem.data.common.currency.CryptoCurrencyFactory import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.visa.model.VisaCardActivationStatus -import com.tangem.domain.wallets.builder.UserWalletIdBuilder -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.extensions.inject import com.tangem.tap.features.demo.DemoHelper -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource -import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction -import com.tangem.tap.features.saveWallet.redux.SaveWalletAction -import com.tangem.tap.mainScope import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.scope import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import timber.log.Timber /** [REDACTED_AUTHOR] */ object OnboardingHelper { suspend fun isOnboardingCase(response: ScanResponse): Boolean { - val onboardingManager = - store.state.globalState.onboardingState.onboardingManager ?: OnboardingManager(response) + val cardRepository = store.inject(DaggerGraphState::cardRepository) val cardId = response.card.cardId + return when { response.cardTypesResolver.isVisaWallet() -> { if (response.visaCardActivationStatus == null) error("Visa card activation status is null") @@ -52,227 +29,20 @@ object OnboardingHelper { if (!response.twinsIsTwinned()) { true } else { - onboardingManager.isActivationInProgress(cardId) + cardRepository.isActivationInProgress(cardId) } } response.cardTypesResolver.isWallet2() || response.cardTypesResolver.isShibaWallet() -> { val emptyWallets = response.card.wallets.isEmpty() - val activationInProgress = onboardingManager.isActivationInProgress(cardId) + val activationInProgress = cardRepository.isActivationInProgress(cardId) val isNoBackup = response.card.backupStatus == CardDTO.BackupStatus.NoBackup && !DemoHelper.isDemoCard(response) emptyWallets || activationInProgress || isNoBackup } - response.card.wallets.isNotEmpty() -> onboardingManager.isActivationInProgress(cardId) + response.card.wallets.isNotEmpty() -> cardRepository.isActivationInProgress(cardId) else -> true } } - - @Suppress("CyclomaticComplexMethod") - fun whereToNavigate(scanResponse: ScanResponse): AppRoute { - val newOnboardingSupportTypes = scanResponse.productType == ProductType.Wallet2 || - scanResponse.productType == ProductType.Ring || - scanResponse.productType == ProductType.Wallet || - scanResponse.productType == ProductType.Visa // AppRoute.OnboardingOther is also supported - val featureToggles = store.inject(DaggerGraphState::onboardingV2FeatureToggles) - if (featureToggles.isOnboardingV2Enabled && - newOnboardingSupportTypes - ) { - val backupState = store.state.onboardingWalletState.backupState - - return AppRoute.Onboarding( - scanResponse = scanResponse, - mode = when (backupState.startedSource) { - BackupStartedSource.Onboarding -> AppRoute.Onboarding.Mode.Onboarding - BackupStartedSource.CreateBackup -> AppRoute.Onboarding.Mode.AddBackupWallet1 - }, - ) - } - - return when (val type = scanResponse.productType) { - ProductType.Note -> if (featureToggles.isNoteRefactoringEnabled) { - AppRoute.Onboarding(scanResponse = scanResponse) - } else { - AppRoute.OnboardingNote - } - ProductType.Wallet, - ProductType.Wallet2, - ProductType.Ring, - -> if (scanResponse.card.settings.isBackupAllowed) { - AppRoute.OnboardingWallet() - } else { - AppRoute.OnboardingOther - } - ProductType.Twins -> if (featureToggles.isTwinRefactoringEnabled) { - AppRoute.Onboarding(scanResponse = scanResponse) - } else { - AppRoute.OnboardingTwins - } - ProductType.Start2Coin, - ProductType.Visa, - -> throw UnsupportedOperationException("Onboarding for ${type.name} cards is not supported") - } - } - - suspend fun saveWallet( - alreadyCreatedWallet: UserWallet?, - scanResponse: ScanResponse, - accessCode: String? = null, - backupCardsIds: List? = null, - hasBackupError: Boolean = false, - ) { - Analytics.setContext(scanResponse) - val settingsRepository = store.inject(DaggerGraphState::settingsRepository) - when { - // When should save user wallets, then save card without navigate to save wallet screen - store.inject(DaggerGraphState::walletsRepository).shouldSaveUserWalletsSync() -> { - store.dispatchWithMain( - SaveWalletAction.ProvideBackupInfo( - scanResponse = scanResponse, - accessCode = accessCode, - backupCardsIds = backupCardsIds?.toSet(), - ), - ) - - store.dispatchWithMain( - SaveWalletAction.SaveWalletAfterBackup( - hasBackupError = hasBackupError, - shouldNavigateToWallet = false, - ), - ) - } - // When should not save user wallets but device has biometry and save wallet screen has not been shown, - // then open save wallet screen - tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen() -> { - proceedWithScanResponse(scanResponse, backupCardsIds, hasBackupError, alreadyCreatedWallet) - - delay(timeMillis = 1_200) - - store.dispatchWithMain( - SaveWalletAction.ProvideBackupInfo( - scanResponse = scanResponse, - accessCode = accessCode, - backupCardsIds = backupCardsIds?.toSet(), - ), - ) - } - // If device has no biometry and save wallet screen has been shown, then go through old scenario - else -> proceedWithScanResponse(scanResponse, backupCardsIds, hasBackupError, alreadyCreatedWallet) - } - } - - fun trySaveWalletAndNavigateToWalletScreen( - scanResponse: ScanResponse, - accessCode: String? = null, - backupCardsIds: List? = null, - hasBackupError: Boolean = false, - ) { - Analytics.setContext(scanResponse) - scope.launch { - val settingsRepository = store.inject(DaggerGraphState::settingsRepository) - - when { - // When should save user wallets, then save card without navigate to save wallet screen - store.inject(DaggerGraphState::walletsRepository).shouldSaveUserWalletsSync() -> { - store.dispatchWithMain( - SaveWalletAction.ProvideBackupInfo( - scanResponse = scanResponse, - accessCode = accessCode, - backupCardsIds = backupCardsIds?.toSet(), - ), - ) - - store.dispatchWithMain( - SaveWalletAction.SaveWalletAfterBackup( - hasBackupError = hasBackupError, - shouldNavigateToWallet = true, - ), - ) - } - // When should not save user wallets but device has biometry and save wallet screen has not been shown, - // then open save wallet screen - tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen() -> { - proceedWithScanResponse(scanResponse, backupCardsIds, hasBackupError) - - delay(timeMillis = 1_200) - - store.dispatchOnMain( - SaveWalletAction.ProvideBackupInfo( - scanResponse = scanResponse, - accessCode = accessCode, - backupCardsIds = backupCardsIds?.toSet(), - ), - ) - store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) } - delay(timeMillis = 1_800) - store.dispatchNavigationAction { push(AppRoute.SaveWallet) } - } - // If device has no biometry and save wallet screen has been shown, then go through old scenario - else -> { - proceedWithScanResponse(scanResponse, backupCardsIds, hasBackupError) - store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) } - } - } - } - } - - fun onInterrupted() { - Analytics.removeContext() - } - - fun sendToppedUpEvent(scanResponse: ScanResponse) { - val userWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build() - val currency = ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver) - - if (userWalletId != null && currency != null) { - Analytics.send(Basic.ToppedUp(userWalletId.stringValue, currency)) - } - } - - fun handleTopUpAction(walletManager: WalletManager, scanResponse: ScanResponse) { - val blockchain = walletManager.wallet.blockchain - val excludedBlockchains = store.inject(DaggerGraphState::excludedBlockchains) - - val cryptoCurrency = CryptoCurrencyFactory(excludedBlockchains).createCoin( - blockchain = blockchain, - extraDerivationPath = null, - scanResponse = scanResponse, - ) ?: return - - val topUpUrl = walletManager.getTopUpUrl(cryptoCurrency) ?: return - - val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain) - Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) - - store.dispatchOpenUrl(topUpUrl) - } - - private suspend fun proceedWithScanResponse( - scanResponse: ScanResponse, - backupCardsIds: List?, - hasBackupError: Boolean, - alreadyCreatedWallet: UserWallet? = null, - ) { - val userWalletBuilderFactory = store.inject(DaggerGraphState::userWalletBuilderFactory) - - val userWallet = alreadyCreatedWallet ?: userWalletBuilderFactory.create(scanResponse) - .hasBackupError(hasBackupError) - .backupCardsIds(backupCardsIds?.toSet()) - .build() - .guard { - Timber.e("User wallet not created") - return - } - - val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) - userWalletsListManager.save(userWallet, canOverride = true) - .doOnFailure { error -> - Timber.e(error, "Unable to save user wallet") - } - .doOnSuccess { - mainScope.launch { store.onUserWalletSelected(userWallet) } - store.dispatchWithMain(OnboardingWalletAction.WalletSaved(userWallet.walletId)) - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt index e982cd5f2e..8ea87b04a4 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt @@ -1,141 +1,6 @@ package com.tangem.tap.features.onboarding -import com.tangem.blockchain.common.AmountType -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.WalletManager -import com.tangem.common.extensions.isZero -import com.tangem.common.services.Result -import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.models.scan.ScanResponse -import com.tangem.operations.attestation.OnlineCardVerifier -import com.tangem.operations.attestation.api.models.CardVerifyAndGetInfo -import com.tangem.tap.common.entities.ProgressState -import com.tangem.tap.common.extensions.inject -import com.tangem.tap.common.extensions.safeUpdate -import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.extensions.getOrLoadCardArtworkUrl -import com.tangem.tap.domain.model.Currency -import com.tangem.tap.domain.model.hasPendingTransactions -import com.tangem.tap.features.demo.isDemoCard -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.store -import com.tangem.utils.extensions.isPositive -import timber.log.Timber -import java.math.BigDecimal -/** -[REDACTED_AUTHOR] - */ @Deprecated("Remove when navigation refactoring will be implemented") -class OnboardingManager(var scanResponse: ScanResponse) { - - private val cardRepository: CardRepository by lazy { store.inject(DaggerGraphState::cardRepository) } - - private val onlineCardVerifier: OnlineCardVerifier by lazy { store.inject(DaggerGraphState::onlineCardVerifier) } - - private var cardInfo: Result? = null - - suspend fun loadArtworkUrl(): String { - val cardInfo = cardInfo - ?: onlineCardVerifier.getCardInfo(scanResponse.card.cardId, scanResponse.card.cardPublicKey) - - this.cardInfo = cardInfo - - return scanResponse.card.getOrLoadCardArtworkUrl(cardInfo, onlineCardVerifier) - } - - suspend fun updateBalance(walletManager: WalletManager): OnboardingWalletBalance { - val isDemoCard = scanResponse.isDemoCard() - val balance = when (val result = walletManager.safeUpdate(isDemoCard)) { - is Result.Success -> { - val wallet = walletManager.wallet - val valueOfAmount = wallet.amounts[AmountType.Coin]?.value - if (valueOfAmount == null) { - val customError = TapError.CustomError("Amount is NULL") - OnboardingWalletBalance.criticalError(customError) - } else { - val balance = if (valueOfAmount.isZero()) { - OnboardingWalletBalance.done(valueOfAmount, wallet.hasPendingTransactions()) - } else { - OnboardingWalletBalance.done(valueOfAmount, false) - } - balance - } - } - is Result.Failure -> { - val error = result.error as? TapError ?: TapError.UnknownError - when (error) { - is TapError.WalletManager.NoAccountError -> OnboardingWalletBalance.error(error) - // NoInternetConnection, WalletManager.InternalError - else -> { - Timber.e(error.localizedMessage) - OnboardingWalletBalance.criticalError(TapError.WalletManager.BlockchainIsUnreachableTryLater) - } - } - } - } - - return balance.copy( - currency = Currency.Blockchain( - blockchain = walletManager.wallet.blockchain, - derivationPath = walletManager.wallet.publicKey.derivationPath?.rawPath, - ), - ) - } - - suspend fun startActivation(cardId: String) { - cardRepository.startCardActivation(cardId) - } - - suspend fun finishActivation(cardId: String) { - cardRepository.finishCardActivation(cardId) - } - - suspend fun finishActivation(cardIds: List) { - cardRepository.finishCardsActivation(cardIds) - } - - suspend fun isActivationStarted(cardId: String): Boolean = cardRepository.isActivationStarted(cardId) - - suspend fun isActivationFinished(cardId: String): Boolean = cardRepository.isActivationFinished(cardId) - - suspend fun isActivationInProgress(cardId: String): Boolean = cardRepository.isActivationInProgress(cardId) -} - -data class OnboardingWalletBalance( - val value: BigDecimal = BigDecimal.ZERO, - val currency: Currency = Currency.Blockchain(Blockchain.Unknown, null), - val hasIncomingTransaction: Boolean = false, - val state: ProgressState, - val error: TapError? = null, - val criticalError: TapError? = null, -) { - - val amountToCreateAccount: String? - get() = if (error is TapError.WalletManager.NoAccountError) error.customMessage else null - - fun balanceIsToppedUp(): Boolean = value.isPositive() || hasIncomingTransaction - - companion object { - fun error(error: TapError): OnboardingWalletBalance = OnboardingWalletBalance( - state = ProgressState.Error, - error = error, - ) - - fun criticalError(error: TapError): OnboardingWalletBalance = OnboardingWalletBalance( - state = ProgressState.Error, - criticalError = error, - ) - - fun loading(value: BigDecimal = BigDecimal.ZERO): OnboardingWalletBalance = OnboardingWalletBalance( - value, - state = ProgressState.Loading, - ) - - fun done(value: BigDecimal, hasTransactions: Boolean): OnboardingWalletBalance = OnboardingWalletBalance( - value, - hasIncomingTransaction = hasTransactions, - state = ProgressState.Done, - ) - } -} \ No newline at end of file +class OnboardingManager(var scanResponse: ScanResponse) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt deleted file mode 100644 index c619d4bd17..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.tangem.tap.features.onboarding - -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import androidx.core.view.MenuProvider -import com.tangem.core.analytics.Analytics -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic -import com.tangem.domain.feedback.models.FeedbackEmailType -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.common.extensions.inject -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.utils.Provider -import com.tangem.wallet.R -import kotlinx.coroutines.launch - -/** -[REDACTED_AUTHOR] - */ -class OnboardingMenuProvider( - private val scanResponseProvider: Provider, -) : MenuProvider { - - override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { - menuInflater.inflate(R.menu.menu_onboarding, menu) - } - - override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) { - R.id.menu_item_chat_support -> { - Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro)) - - val cardInfo = store.inject(DaggerGraphState::getCardInfoUseCase).invoke(scanResponseProvider()).getOrNull() - ?: error("CardInfo must be not null") - - scope.launch { - store.inject(DaggerGraphState::sendFeedbackEmailUseCase) - .invoke(type = FeedbackEmailType.DirectUserRequest(cardInfo)) - } - - true - } - else -> false - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt deleted file mode 100644 index 0922d3f023..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.tangem.tap.features.onboarding.products - -import android.os.Bundle -import android.view.View -import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.MenuProvider -import by.kirich1409.viewbindingdelegate.viewBinding -import com.tangem.tap.common.extensions.show -import com.tangem.tap.common.transitions.HomeToOnboardingTransition -import com.tangem.tap.features.BaseStoreFragment -import com.tangem.tap.features.onboarding.OnboardingMenuProvider -import com.tangem.tap.store -import com.tangem.utils.Provider -import com.tangem.wallet.R -import com.tangem.wallet.databinding.FragmentOnboardingMainBinding -import com.tangem.wallet.databinding.ViewOnboardingProgressBinding -import org.rekotlin.StoreSubscriber - -/** -[REDACTED_AUTHOR] - */ -abstract class BaseOnboardingFragment : BaseStoreFragment(R.layout.fragment_onboarding_main), StoreSubscriber { - - protected val binding: FragmentOnboardingMainBinding by viewBinding(FragmentOnboardingMainBinding::bind) - protected val pbBinding: ViewOnboardingProgressBinding by viewBinding(ViewOnboardingProgressBinding::bind) - - override fun configureTransitions() { - enterTransition = HomeToOnboardingTransition() - exitTransition = HomeToOnboardingTransition() - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - (activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar) - } - - override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider( - scanResponseProvider = Provider { - store.state.globalState.onboardingState.onboardingManager?.scanResponse - ?: store.state.detailsState.scanResponse - ?: error("ScanResponse must be not null") - }, - ) - - protected fun showConfetti(show: Boolean) = with(binding.vConfetti) { - lavConfetti.show(show) - - if (show) { - lavConfetti.playAnimation() - } else { - lavConfetti.cancelAnimation() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt deleted file mode 100644 index 8346f444cd..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ /dev/null @@ -1,228 +0,0 @@ -package com.tangem.tap.features.onboarding.products.note - -import android.os.Bundle -import android.view.View -import android.view.animation.OvershootInterpolator -import androidx.annotation.LayoutRes -import androidx.constraintlayout.widget.ConstraintSet -import androidx.core.view.isVisible -import androidx.transition.TransitionManager -import coil.load -import com.tangem.blockchain.common.Blockchain -import com.tangem.core.analytics.Analytics -import com.tangem.core.navigation.ShareElement -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.getDrawableCompat -import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget -import com.tangem.tap.common.transitions.InternalNoteLayoutTransition -import com.tangem.tap.features.addBackPressHandler -import com.tangem.tap.features.onboarding.OnboardingWalletBalance -import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment -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.products.note.redux.OnboardingNoteStep -import com.tangem.tap.store -import com.tangem.utils.extensions.stripZeroPlainString -import com.tangem.wallet.R - -@Deprecated("Use OnboardingNoteComponent") -class OnboardingNoteFragment : BaseOnboardingFragment() { - - private var previousStep: OnboardingNoteStep = OnboardingNoteStep.None - private val mainBinding by lazy { binding.vMain } - - private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - addBackPressHandler(this) - - mainBinding.onboardingTopContainer.imvFrontCard.transitionName = ShareElement.imvFrontCard - - binding.toolbar.setTitle(R.string.onboarding_title) - btnRefreshBalanceWidget = RefreshBalanceWidget(mainBinding.onboardingTopContainer.onboardingWalletContainer) - - store.dispatch(OnboardingNoteAction.Init) - store.dispatch(OnboardingNoteAction.LoadCardArtwork) - store.dispatch(OnboardingNoteAction.DetermineStepOfScreen) - } - - override fun subscribeToStore() { - store.subscribe(this) { state -> - state.skipRepeats { oldState, newState -> - oldState.onboardingNoteState == newState.onboardingNoteState - }.select { it.onboardingNoteState } - } - storeSubscribersList.add(this) - } - - override fun newState(state: OnboardingNoteState) { - if (activity == null || view == null) return - - mainBinding.onboardingTopContainer.imvFrontCard.load(state.cardArtworkUrl) { - placeholder(R.drawable.card_placeholder_black) - error(R.drawable.card_placeholder_black) - fallback(R.drawable.card_placeholder_black) - } - - pbBinding.pbState.max = state.steps.size - 1 - pbBinding.pbState.progress = state.progress - - when (state.currentStep) { - OnboardingNoteStep.None -> setupNoneState() - OnboardingNoteStep.CreateWallet -> setupCreateWalletState(state) - OnboardingNoteStep.TopUpWallet -> setupTopUpWalletState(state) - OnboardingNoteStep.Done -> setupDoneState(state) - } - setBalance(state) - showConfetti(state.showConfetti) - previousStep = state.currentStep - } - - private fun setBalance(state: OnboardingNoteState) { - if (state.walletBalance.currency.blockchain == Blockchain.Unknown) return - - with(mainBinding.onboardingTopContainer.onboardingTvBalance) { - if (state.balanceCriticalError == null) { - val balanceValue = state.walletBalance.value.stripZeroPlainString() - tvBalanceValue.text = balanceValue - tvBalanceCurrency.text = state.walletBalance.currency.currencySymbol - } else { - tvBalanceValue.text = "–" - tvBalanceCurrency.text = "" - } - } - } - - private fun setupNoneState() = with(mainBinding.onboardingActionContainer) { - btnMainAction.isVisible = false - btnAlternativeAction.isVisible = false - btnRefreshBalanceWidget.show(false) - tvHeader.isVisible = false - tvBody.isVisible = false - - btnMainAction.text = "" - btnMainAction.icon = null - btnAlternativeAction.text = "" - btnAlternativeAction.icon = null - tvHeader.text = "" - tvBody.text = "" - } - - private fun setupCreateWalletState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { - btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) - btnMainAction.setIconResource(R.drawable.ic_tangem_24) - btnMainAction.setOnClickListener { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) - store.dispatch(OnboardingNoteAction.CreateWallet) - } - btnAlternativeAction.setText(R.string.onboarding_button_what_does_it_mean) - btnAlternativeAction.setOnClickListener { } - - btnRefreshBalanceWidget.mainView.setOnClickListener(null) - - tvHeader.setText(R.string.onboarding_create_wallet_header) - tvBody.setText(R.string.onboarding_create_wallet_body) - - mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable( - requireContext().getDrawableCompat(R.drawable.shape_circle), - ) - updateConstraints(state.currentStep, R.layout.lp_onboarding_create_wallet) - - btnAlternativeAction.isVisible = false // temporary - } - - private fun setupTopUpWalletState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { - if (availableForBuy(state.scanResponse, state.walletBalance)) { - btnMainAction.setText(R.string.onboarding_top_up_button_but_crypto) - btnMainAction.icon = null - btnMainAction.setOnClickListener { - store.dispatch(OnboardingNoteAction.TopUp) - } - - btnAlternativeAction.isVisible = true - btnAlternativeAction.setText(R.string.onboarding_top_up_button_show_wallet_address) - btnAlternativeAction.setOnClickListener { - store.dispatch(OnboardingNoteAction.ShowAddressInfoDialog) - } - } else { - btnMainAction.setText(R.string.onboarding_button_receive_crypto) - btnMainAction.icon = null - btnMainAction.setOnClickListener { - store.dispatch(OnboardingNoteAction.ShowAddressInfoDialog) - } - - btnAlternativeAction.isVisible = false - } - - tvHeader.setText(R.string.onboarding_topup_title) - if (state.balanceNonCriticalError == null) { - tvBody.setText(R.string.onboarding_top_up_body) - } else { - state.walletBalance.amountToCreateAccount?.let { amount -> - val tvBodyMessage = getString( - R.string.onboarding_top_up_body_no_account_error, - amount, - state.walletBalance.currency.currencySymbol, - ) - tvBody.text = tvBodyMessage - } - } - - btnRefreshBalanceWidget.changeState(state.walletBalance.state) - if (btnRefreshBalanceWidget.isShowing != true) { - btnRefreshBalanceWidget.mainView.setOnClickListener { - store.dispatch(OnboardingNoteAction.Balance.Update) - } - } - - val drawable = requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8) - mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable(drawable) - updateConstraints(state.currentStep, R.layout.lp_onboarding_topup_wallet) - } - - private fun setupDoneState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { - btnMainAction.setText(R.string.common_continue) - btnMainAction.icon = null - btnMainAction.setOnClickListener { - showConfetti(false) - store.dispatch(OnboardingNoteAction.Done) - } - - btnAlternativeAction.isVisible = false - btnAlternativeAction.text = "" - btnAlternativeAction.setOnClickListener { } - btnRefreshBalanceWidget.mainView.setOnClickListener(null) - - tvHeader.setText(R.string.onboarding_done_header) - tvBody.setText(R.string.onboarding_done_body) - - mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable( - requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8), - ) - updateConstraints(state.currentStep, R.layout.lp_onboarding_done_activation) - } - - private fun updateConstraints(currentStep: OnboardingNoteStep, @LayoutRes layoutId: Int) { - if (this.previousStep == currentStep) return - - with(mainBinding.onboardingTopContainer) { - val constraintSet = ConstraintSet() - constraintSet.clone(requireContext(), layoutId) - constraintSet.applyTo(onboardingWalletContainer) - val transition = InternalNoteLayoutTransition() - transition.interpolator = OvershootInterpolator() - TransitionManager.beginDelayedTransition(onboardingWalletContainer, transition) - } - } - - private fun availableForBuy(scanResponse: ScanResponse?, walletBalance: OnboardingWalletBalance): Boolean { - scanResponse ?: return false - return store.state.globalState.exchangeManager.availableForBuy(scanResponse, walletBalance.currency) - } - - override fun handleOnBackPressed() { - store.dispatch(OnboardingNoteAction.OnBackPressed) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt deleted file mode 100644 index ebdf31becb..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.tangem.tap.features.onboarding.products.note.redux - -import com.tangem.blockchain.common.WalletManager -import com.tangem.tap.domain.TapError -import com.tangem.tap.features.onboarding.OnboardingWalletBalance -import org.rekotlin.Action - -/** -[REDACTED_AUTHOR] - */ -sealed class OnboardingNoteAction : Action { - // from user, ui - object Init : OnboardingNoteAction() - object LoadCardArtwork : OnboardingNoteAction() - object CreateWallet : OnboardingNoteAction() - object TopUp : OnboardingNoteAction() - object ShowAddressInfoDialog : OnboardingNoteAction() - object OnBackPressed : OnboardingNoteAction() - - // from redux - class SetArtworkUrl(val artworkUrl: String) : OnboardingNoteAction() - data class SetWalletManager(val walletManager: WalletManager) : OnboardingNoteAction() - object DetermineStepOfScreen : OnboardingNoteAction() - object Done : OnboardingNoteAction() - - data class SetStepOfScreen(val step: OnboardingNoteStep) : OnboardingNoteAction() - - sealed class Balance { - object Update : OnboardingNoteAction() - data class Set(val balance: OnboardingWalletBalance) : OnboardingNoteAction() - data class SetCriticalError(val error: TapError?) : OnboardingNoteAction() - data class SetNonCriticalError(val error: TapError?) : OnboardingNoteAction() - } - - sealed class Confetti { - object Show : OnboardingNoteAction() - object Hide : OnboardingNoteAction() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt deleted file mode 100644 index 99c704189c..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.tangem.tap.features.onboarding.products.note.redux - -import com.tangem.common.CompletionResult -import com.tangem.common.extensions.guard -import com.tangem.common.routing.AppRouter -import com.tangem.core.analytics.Analytics -import com.tangem.domain.common.extensions.makePrimaryWalletManager -import com.tangem.domain.common.extensions.withMainContext -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.entities.ProgressState -import com.tangem.tap.common.extensions.* -import com.tangem.tap.common.postUi -import com.tangem.tap.common.redux.AppDialog -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.model.Currency -import com.tangem.tap.features.demo.DemoHelper -import com.tangem.tap.features.onboarding.OnboardingDialog -import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.mainScope -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.rekotlin.Action -import org.rekotlin.DispatchFunction -import org.rekotlin.Middleware - -object OnboardingNoteMiddleware { - val handler = onboardingNoteMiddleware -} - -private val onboardingNoteMiddleware: Middleware = { dispatch, state -> - { next -> - { action -> - handleNoteAction(state, action, dispatch) - next(action) - } - } -} - -@Suppress("LongMethod", "ComplexMethod", "MagicNumber") -private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch: DispatchFunction) { - if (action !is OnboardingNoteAction) return - if (DemoHelper.tryHandle(appState, action)) return - - val globalState = store.state.globalState - val onboardingManager = globalState.onboardingState.onboardingManager ?: return - - val scanResponse = onboardingManager.scanResponse - val card = onboardingManager.scanResponse.card - val noteState = store.state.onboardingNoteState - - when (action) { - is OnboardingNoteAction.Init -> { - scope.launch { - if (!onboardingManager.isActivationStarted(card.cardId)) { - Analytics.send(Onboarding.Started()) - } - } - } - is OnboardingNoteAction.LoadCardArtwork -> { - scope.launch { - val artworkUrl = onboardingManager.loadArtworkUrl() - withMainContext { store.dispatch(OnboardingNoteAction.SetArtworkUrl(artworkUrl)) } - } - } - is OnboardingNoteAction.DetermineStepOfScreen -> { - val step = when { - card.wallets.isEmpty() -> OnboardingNoteStep.CreateWallet - noteState.walletBalance.balanceIsToppedUp() -> OnboardingNoteStep.Done - else -> OnboardingNoteStep.TopUpWallet - } - store.dispatch(OnboardingNoteAction.SetStepOfScreen(step)) - } - is OnboardingNoteAction.SetStepOfScreen -> { - when (action.step) { - OnboardingNoteStep.CreateWallet -> { - Analytics.send(Onboarding.CreateWallet.ScreenOpened()) - } - OnboardingNoteStep.TopUpWallet -> { - Analytics.send(Onboarding.Topup.ScreenOpened()) - store.dispatch(OnboardingNoteAction.Balance.Update) - } - OnboardingNoteStep.Done -> { - Analytics.send(Onboarding.Finished()) - mainScope.launch { - onboardingManager.finishActivation(card.cardId) - postUi(DELAY_SDK_DIALOG_CLOSE) { store.dispatch(OnboardingNoteAction.Confetti.Show) } - } - } - else -> Unit - } - } - is OnboardingNoteAction.CreateWallet -> { - scope.launch { - val result = tangemSdkManager.createProductWallet(scanResponse) - withMainContext { - when (result) { - is CompletionResult.Success -> { - Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) - val updatedResponse = scanResponse.copy(card = result.data.card) - onboardingManager.scanResponse = updatedResponse - onboardingManager.startActivation(updatedResponse.card.cardId) - store.dispatch(OnboardingNoteAction.SetStepOfScreen(OnboardingNoteStep.TopUpWallet)) - } - is CompletionResult.Failure -> Unit - } - } - } - } - is OnboardingNoteAction.Balance.Update -> { - val walletManager = if (noteState.walletManager != null) { - noteState.walletManager - } else { - val wmFactory = runBlocking { - store.inject(DaggerGraphState::blockchainSDKFactory).getWalletManagerFactorySync() - } - val walletManager = wmFactory?.makePrimaryWalletManager(scanResponse).guard { - val message = "Loading cancelled. Cause: wallet manager didn't created" - val customError = TapError.CustomError(message) - store.dispatchErrorNotification(customError) - return - } - dispatch(OnboardingNoteAction.SetWalletManager(walletManager)) - walletManager - } - - val isLoadedBefore = noteState.walletBalance.state != ProgressState.Loading - val balanceIsLoading = noteState.walletBalance.copy( - currency = Currency.Blockchain( - walletManager.wallet.blockchain, - walletManager.wallet.publicKey.derivationPath?.rawPath, - ), - state = ProgressState.Loading, - error = null, - criticalError = null, - ) - store.dispatch(OnboardingNoteAction.Balance.Set(balanceIsLoading)) - - scope.launch { - val loadedBalance = onboardingManager.updateBalance(walletManager) - delay(if (isLoadedBefore) 0 else 300) - loadedBalance.criticalError?.let { store.dispatchErrorNotification(it) } - withMainContext { - store.dispatch(OnboardingNoteAction.Balance.Set(loadedBalance)) - store.dispatch(OnboardingNoteAction.Balance.SetCriticalError(loadedBalance.criticalError)) - store.dispatch(OnboardingNoteAction.Balance.SetNonCriticalError(loadedBalance.error)) - } - } - } - is OnboardingNoteAction.Balance.Set -> { - if (action.balance.balanceIsToppedUp()) { - OnboardingHelper.sendToppedUpEvent(scanResponse) - store.dispatch(OnboardingNoteAction.SetStepOfScreen(OnboardingNoteStep.Done)) - } - } - is OnboardingNoteAction.ShowAddressInfoDialog -> { - val addressData = noteState.walletManager?.getAddressData() ?: return - - Analytics.send(Onboarding.Topup.ButtonShowWalletAddress()) - val appDialog = AppDialog.AddressInfoDialog(noteState.walletBalance.currency, addressData) - store.dispatchDialogShow(appDialog) - } - is OnboardingNoteAction.TopUp -> { - val walletManager = noteState.walletManager.guard { - store.dispatchDebugErrorNotification("NPE: WalletManager") - return - } - - OnboardingHelper.handleTopUpAction( - walletManager = walletManager, - scanResponse = scanResponse, - ) - } - is OnboardingNoteAction.Done -> { - store.dispatch(GlobalAction.Onboarding.Stop) - OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse) - } - is OnboardingNoteAction.OnBackPressed -> { - store.dispatchDialogShow( - OnboardingDialog.InterruptOnboarding( - onOk = { - OnboardingHelper.onInterrupted() - store.dispatchNavigationAction(AppRouter::pop) - }, - ), - ) - } - else -> Unit - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt deleted file mode 100644 index 14f7989391..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteReducer.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.tangem.tap.features.onboarding.products.note.redux - -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction -import org.rekotlin.Action - -object OnboardingNoteReducer { - 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 GlobalAction.Onboarding.Start -> { - state = OnboardingNoteState(scanResponse = action.scanResponse) - } - is OnboardingNoteAction.SetArtworkUrl -> { - state = state.copy(cardArtworkUrl = action.artworkUrl) - } - is OnboardingNoteAction.SetWalletManager -> { - state = state.copy(walletManager = action.walletManager) - } - is OnboardingNoteAction.Balance.Set -> { - state = state.copy(walletBalance = action.balance) - } - is OnboardingNoteAction.Balance.SetCriticalError -> { - state = state.copy(balanceCriticalError = action.error) - } - is OnboardingNoteAction.Balance.SetNonCriticalError -> { - state = state.copy(balanceNonCriticalError = action.error) - } - is OnboardingNoteAction.SetStepOfScreen -> { - if (action.step != state.currentStep && state.steps.contains(action.step)) { - state = state.copy(currentStep = action.step) - } - } - is OnboardingNoteAction.Confetti.Show -> { - state = state.copy(showConfetti = true) - } - is OnboardingNoteAction.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/note/redux/OnboardingNoteState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt deleted file mode 100644 index 3d659e39da..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteState.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.tangem.tap.features.onboarding.products.note.redux - -import com.tangem.blockchain.common.WalletManager -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.domain.TapError -import com.tangem.tap.features.onboarding.OnboardingWalletBalance -import org.rekotlin.StateType - -/** -[REDACTED_AUTHOR] - */ -data class OnboardingNoteState( - val walletManager: WalletManager? = null, - // UI - val cardArtworkUrl: String? = null, - val walletBalance: OnboardingWalletBalance = OnboardingWalletBalance.loading(), - val balanceNonCriticalError: TapError? = null, - val balanceCriticalError: TapError? = null, - val currentStep: OnboardingNoteStep = OnboardingNoteStep.None, - val steps: List = OnboardingNoteStep.values().toList(), - val showConfetti: Boolean = false, - val scanResponse: ScanResponse? = null, -) : StateType { - - val progress: Int - get() = steps.indexOf(currentStep) -} - -enum class OnboardingNoteStep { - None, CreateWallet, TopUpWallet, Done -} \ No newline at end of file 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 deleted file mode 100644 index 2e6ac715e0..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ /dev/null @@ -1,128 +0,0 @@ -package com.tangem.tap.features.onboarding.products.otherCards - -import android.os.Bundle -import android.view.View -import android.view.animation.OvershootInterpolator -import androidx.annotation.LayoutRes -import androidx.constraintlayout.widget.ConstraintSet -import androidx.core.view.isVisible -import androidx.transition.TransitionManager -import coil.load -import com.tangem.core.analytics.Analytics -import com.tangem.core.navigation.ShareElement -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.getDrawableCompat -import com.tangem.tap.common.transitions.InternalNoteLayoutTransition -import com.tangem.tap.features.addBackPressHandler -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 - -/** -[REDACTED_AUTHOR] - */ -class OnboardingOtherCardsFragment : BaseOnboardingFragment() { - - private val mainBinding by lazy { binding.vMain } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - addBackPressHandler(this) - - mainBinding.onboardingTopContainer.imvFrontCard.transitionName = ShareElement.imvFrontCard - - binding.toolbar.setTitle(R.string.onboarding_title) - store.dispatch(OnboardingOtherCardsAction.Init) - store.dispatch(OnboardingOtherCardsAction.LoadCardArtwork) - store.dispatch(OnboardingOtherCardsAction.DetermineStepOfScreen) - } - - override fun subscribeToStore() { - 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 || view == null) return - if (state.currentStep == OnboardingOtherCardsStep.None) return - - mainBinding.onboardingTopContainer.imvFrontCard.load(state.cardArtworkUrl) { - placeholder(R.drawable.card_placeholder_black) - error(R.drawable.card_placeholder_black) - fallback(R.drawable.card_placeholder_black) - } - - pbBinding.pbState.max = state.steps.size - 1 - pbBinding.pbState.progress = state.progress - - when (state.currentStep) { - OnboardingOtherCardsStep.CreateWallet -> setupCreateWalletState() - OnboardingOtherCardsStep.Done -> setupDoneState() - else -> {} - } - showConfetti(state.showConfetti) - } - - private fun setupCreateWalletState() = with(mainBinding.onboardingActionContainer) { - btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) - btnMainAction.setIconResource(R.drawable.ic_tangem_24) - btnMainAction.setOnClickListener { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) - store.dispatch(OnboardingOtherCardsAction.CreateWallet) - } - btnAlternativeAction.setText(R.string.onboarding_button_what_does_it_mean) - btnAlternativeAction.setOnClickListener { } - - tvHeader.setText(R.string.onboarding_create_wallet_header) - tvBody.setText(R.string.onboarding_create_wallet_body) - - btnAlternativeAction.isVisible = false // temporary - - mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable( - requireContext().getDrawableCompat(R.drawable.shape_circle), - ) - updateConstraints(R.layout.lp_onboarding_create_wallet) - } - - private fun setupDoneState() = with(mainBinding.onboardingActionContainer) { - btnMainAction.setText(R.string.common_continue) - btnMainAction.icon = null - btnMainAction.setOnClickListener { - showConfetti(false) - store.dispatch(OnboardingOtherCardsAction.Done) - } - - btnAlternativeAction.isVisible = false - btnAlternativeAction.text = "" - btnAlternativeAction.setOnClickListener { } - - tvHeader.setText(R.string.onboarding_done_header) - tvBody.setText(R.string.onboarding_done_body) - - mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable( - requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8), - ) - updateConstraints(R.layout.lp_onboarding_done) - } - - private fun updateConstraints(@LayoutRes layoutId: Int) = with(mainBinding.onboardingTopContainer) { - val constraintSet = ConstraintSet() - constraintSet.clone(requireContext(), layoutId) - constraintSet.applyTo(onboardingWalletContainer) - val transition = InternalNoteLayoutTransition() - transition.interpolator = OvershootInterpolator() - TransitionManager.beginDelayedTransition(onboardingWalletContainer, transition) - } - - override fun handleOnBackPressed() { - store.dispatch(OnboardingOtherCardsAction.OnBackPressed) - super.handleOnBackPressed() - } -} \ 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 deleted file mode 100644 index 60c3c3927d..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsAction.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.tangem.tap.features.onboarding.products.otherCards.redux - -import org.rekotlin.Action - -/** -[REDACTED_AUTHOR] - */ -sealed class OnboardingOtherCardsAction : Action { - // from user, ui - object Init : OnboardingOtherCardsAction() - object LoadCardArtwork : OnboardingOtherCardsAction() - object CreateWallet : OnboardingOtherCardsAction() - - // from redux - class SetArtworkUrl(val artworkUrl: String) : OnboardingOtherCardsAction() - object DetermineStepOfScreen : OnboardingOtherCardsAction() - object Done : OnboardingOtherCardsAction() - object OnBackPressed : 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 deleted file mode 100644 index d5e8144485..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.tangem.tap.features.onboarding.products.otherCards.redux - -import com.tangem.common.CompletionResult -import com.tangem.common.core.TangemSdkError -import com.tangem.core.analytics.Analytics -import com.tangem.domain.common.extensions.withMainContext -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.dispatchDialogShow -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.features.onboarding.OnboardingDialog -import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.mainScope -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.rekotlin.Action -import org.rekotlin.Middleware - -object OnboardingOtherCardsMiddleware { - val handler = onboardingOtherCardsMiddleware -} - -private val onboardingOtherCardsMiddleware: Middleware = { dispatch, _ -> - { next -> - { action -> - handleOtherCardsAction(action) - next(action) - } - } -} - -@Suppress("LongMethod", "ComplexMethod", "MagicNumber") -private fun handleOtherCardsAction(action: Action) { - if (action !is OnboardingOtherCardsAction) return - val globalState = store.state.globalState - val onboardingManager = globalState.onboardingState.onboardingManager ?: return - - val card = onboardingManager.scanResponse.card - - when (action) { - is OnboardingOtherCardsAction.Init -> { - scope.launch { - if (!onboardingManager.isActivationStarted(card.cardId)) { - Analytics.send(Onboarding.Started()) - } - } - } - is OnboardingOtherCardsAction.LoadCardArtwork -> { - scope.launch { - val artworkUrl = onboardingManager.loadArtworkUrl() - withMainContext { store.dispatch(OnboardingOtherCardsAction.SetArtworkUrl(artworkUrl)) } - } - } - is OnboardingOtherCardsAction.DetermineStepOfScreen -> { - val step = when { - card.wallets.isEmpty() -> OnboardingOtherCardsStep.CreateWallet - else -> OnboardingOtherCardsStep.Done - } - store.dispatch(OnboardingOtherCardsAction.SetStepOfScreen(step)) - } - is OnboardingOtherCardsAction.SetStepOfScreen -> { - when (action.step) { - OnboardingOtherCardsStep.CreateWallet -> { - Analytics.send(Onboarding.CreateWallet.ScreenOpened()) - } - OnboardingOtherCardsStep.Done -> { - Analytics.send(Onboarding.Finished()) - mainScope.launch { - onboardingManager.finishActivation(card.cardId) - postUi(200) { store.dispatch(OnboardingOtherCardsAction.Confetti.Show) } - } - } - else -> Unit - } - } - is OnboardingOtherCardsAction.CreateWallet -> { - scope.launch { - val result = tangemSdkManager.createProductWallet( - scanResponse = onboardingManager.scanResponse, - shouldReset = globalState.onboardingState.shouldResetOnCreate, - ) - withMainContext { - when (result) { - is CompletionResult.Success -> { - Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) - val updatedResponse = onboardingManager.scanResponse.copy( - card = result.data.card, - ) - val updatedCard = updatedResponse.card - onboardingManager.scanResponse = updatedResponse - onboardingManager.startActivation(updatedCard.cardId) - - delay(DELAY_SDK_DIALOG_CLOSE) - store.dispatch(OnboardingOtherCardsAction.SetStepOfScreen(OnboardingOtherCardsStep.Done)) - } - is CompletionResult.Failure -> { - if (result.error is TangemSdkError.WalletAlreadyCreated) { - handleActivationError() - } - } - } - } - } - } - OnboardingOtherCardsAction.Done -> { - store.dispatch(GlobalAction.Onboarding.Stop) - OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(onboardingManager.scanResponse) - } - OnboardingOtherCardsAction.OnBackPressed -> { - OnboardingHelper.onInterrupted() - } - else -> Unit - } -} - -private fun handleActivationError() { - store.dispatchDialogShow( - OnboardingDialog.WalletActivationError( - onConfirm = { - store.dispatch(GlobalAction.Onboarding.ShouldResetCardOnCreate(true)) - }, - ), - ) -} \ 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 deleted file mode 100644 index 3dae886ef6..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsReducer.kt +++ /dev/null @@ -1,35 +0,0 @@ -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 org.rekotlin.Action - -object OnboardingOtherCardsReducer { - 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.Start -> { - state = OnboardingOtherCardsState() - } - is OnboardingOtherCardsAction.SetArtworkUrl -> { - state = state.copy(cardArtworkUrl = action.artworkUrl) - } - 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 deleted file mode 100644 index f502350050..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsState.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.tangem.tap.features.onboarding.products.otherCards.redux - -import org.rekotlin.StateType - -/** -[REDACTED_AUTHOR] - */ -data class OnboardingOtherCardsState( - // UI - val cardArtworkUrl: String? = null, - val showConfetti: Boolean = false, - 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/products/twins/redux/TwinCardsAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt deleted file mode 100644 index ca00a0c255..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.tangem.tap.features.onboarding.products.twins.redux - -import com.tangem.Message -import com.tangem.blockchain.common.WalletManager -import com.tangem.common.extensions.VoidCallback -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.twins.TwinCardsManager -import com.tangem.tap.features.onboarding.OnboardingWalletBalance -import org.rekotlin.Action - -/** -[REDACTED_AUTHOR] - */ -sealed class TwinCardsAction : Action { - data class IfTwinsPrepareState(val scanResponse: ScanResponse) : TwinCardsAction() - - object Init : TwinCardsAction() - data class SetMode(val mode: CreateTwinWalletMode) : TwinCardsAction() - data class SetStepOfScreen(val step: TwinCardsStep) : TwinCardsAction() - data class SetUserUnderstand(val isUnderstand: Boolean) : TwinCardsAction() - - sealed class CardsManager { - data class Set(val manager: TwinCardsManager) : TwinCardsAction() - object Release : TwinCardsAction() - } - - sealed class Wallet : TwinCardsAction() { - data class LaunchFirstStep(val initialMessage: Message) : TwinCardsAction() - data class LaunchSecondStep( - val initialMessage: Message, - val preparingMessage: Message, - val creatingWalletMessage: Message, - ) : TwinCardsAction() - - data class LaunchThirdStep(val message: Message) : TwinCardsAction() - } - - // for the onboarding - data class SetPairCardId(val cardId: String) : TwinCardsAction() - object TopUp : TwinCardsAction() - object ShowAddressInfoDialog : TwinCardsAction() - data class SetWalletManager(val walletManager: WalletManager) : TwinCardsAction() - object Done : TwinCardsAction() - - data class OnBackPressed( - // this is necessary for the correct animation of the return of cards to the Home screen - val shouldResetTwinCardsWidget: (should: Boolean, popAction: VoidCallback) -> Unit, - ) : TwinCardsAction() - - data class SaveScannedTwinCardAndNavigateToWallet( - val scanResponse: ScanResponse, - ) : TwinCardsAction() - - sealed class Balance { - object Update : TwinCardsAction() - data class Set(val balance: OnboardingWalletBalance) : TwinCardsAction() - data class SetCriticalError(val error: TapError?) : TwinCardsAction() - data class SetNonCriticalError(val error: TapError?) : TwinCardsAction() - } - - sealed class Confetti { - object Show : TwinCardsAction() - object Hide : TwinCardsAction() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt deleted file mode 100644 index 9b0daea01d..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ /dev/null @@ -1,399 +0,0 @@ -package com.tangem.tap.features.onboarding.products.twins.redux - -import com.tangem.common.CompletionResult -import com.tangem.common.core.TangemError -import com.tangem.common.core.TangemSdkError -import com.tangem.common.extensions.guard -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.utils.popTo -import com.tangem.core.analytics.Analytics -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent -import com.tangem.core.ui.R -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.toWrappedList -import com.tangem.core.ui.message.dialog.Dialogs -import com.tangem.domain.common.extensions.makePrimaryWalletManager -import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.common.util.twinsIsTwinned -import com.tangem.domain.feedback.models.FeedbackEmailType -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.wallets.builder.UserWalletIdBuilder -import com.tangem.domain.wallets.legacy.asLockable -import com.tangem.sdk.extensions.localizedDescriptionRes -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.entities.ProgressState -import com.tangem.tap.common.extensions.* -import com.tangem.tap.common.postUi -import com.tangem.tap.common.redux.AppDialog -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.model.Currency -import com.tangem.tap.domain.twins.TwinCardsManager -import com.tangem.tap.features.onboarding.OnboardingDialog -import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.mainScope -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.rekotlin.Action -import org.rekotlin.DispatchFunction -import org.rekotlin.Middleware -import kotlin.reflect.KClass - -object TwinCardsMiddleware { - val handler = twinsWalletMiddleware -} - -private val twinsWalletMiddleware: Middleware = { dispatch, _ -> - { next -> - { action -> - handle(action, dispatch) - next(action) - } - } -} - -@Suppress("LongMethod", "ComplexMethod", "MagicNumber") -private fun handle(action: Action, dispatch: DispatchFunction) { - if (action !is TwinCardsAction) return - - val globalState = store.state.globalState - val onboardingManager = globalState.onboardingState.onboardingManager - val twinCardsState = store.state.twinCardsState - val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) - - fun getScanResponse(): ScanResponse { - return when (twinCardsState.mode) { - is CreateTwinWalletMode.CreateWallet -> onboardingManager?.scanResponse - is CreateTwinWalletMode.RecreateWallet -> globalState.scanResponse - } ?: throw NullPointerException("ScanResponse can't be NULL") - } - - fun updateScanResponse(response: ScanResponse) { - when (twinCardsState.mode) { - is CreateTwinWalletMode.CreateWallet -> onboardingManager?.scanResponse = response - is CreateTwinWalletMode.RecreateWallet -> store.dispatchOnMain(GlobalAction.SaveScanResponse(response)) - } - } - - fun startCardActivation(cardId: String) { - if (twinCardsState.mode == CreateTwinWalletMode.CreateWallet) { - scope.launch { - onboardingManager?.startActivation(cardId) - } - } - } - - fun finishCardActivation() { - if (twinCardsState.mode == CreateTwinWalletMode.CreateWallet) { - Analytics.send(Onboarding.Finished()) - - val cardIds = listOfNotNull(getScanResponse().card.cardId, twinCardsState.pairCardId) - - if (cardIds.isNotEmpty()) { - mainScope.launch { - onboardingManager?.finishActivation(cardIds) - } - } - } - } - - when (action) { - is TwinCardsAction.Init -> { - mainScope.launch { - if (twinCardsState.currentStep is TwinCardsStep.WelcomeOnly) return@launch - - if (twinCardsState.mode is CreateTwinWalletMode.RecreateWallet) { - store.dispatch(GlobalAction.SaveScanResponse(twinCardsState.mode.scanResponse)) - } - - val scanResponse = getScanResponse() - onboardingManager?.apply { - if (!isActivationStarted(scanResponse.card.cardId)) { - Analytics.send(Onboarding.Started()) - } - } - - when (twinCardsState.mode) { - is CreateTwinWalletMode.CreateWallet -> { - mainScope.launch { - val wasTwinsOnboardingShown = store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase) - .invokeSync() - - val dispatchAction = if (wasTwinsOnboardingShown) { - val step = when { - !scanResponse.twinsIsTwinned() -> TwinCardsStep.CreateFirstWallet - twinCardsState.walletBalance.balanceIsToppedUp() -> TwinCardsStep.Done - else -> TwinCardsStep.TopUpWallet - } - TwinCardsAction.SetStepOfScreen(step) - } else { - TwinCardsAction.SetStepOfScreen(TwinCardsStep.Welcome) - } - - store.dispatch(dispatchAction) - } - } - is CreateTwinWalletMode.RecreateWallet -> { - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Warning)) - } - } - } - } - is TwinCardsAction.SetStepOfScreen -> { - when (action.step) { - is TwinCardsStep.WelcomeOnly, TwinCardsStep.Welcome -> { - Analytics.send(Onboarding.Twins.ScreenOpened()) - - scope.launch { - store.inject(DaggerGraphState::saveTwinsOnboardingShownUseCase).invoke() - } - } - is TwinCardsStep.CreateFirstWallet -> { - Analytics.send(Onboarding.CreateWallet.ScreenOpened()) - Analytics.send(Onboarding.Twins.SetupStarted()) - } - TwinCardsStep.TopUpWallet -> { - Analytics.send(Onboarding.Topup.ScreenOpened()) - store.dispatch(TwinCardsAction.Balance.Update) - } - TwinCardsStep.Done -> { - finishCardActivation() - postUi(500) { store.dispatch(TwinCardsAction.Confetti.Show) } - } - TwinCardsStep.None, - TwinCardsStep.Warning, - TwinCardsStep.CreateSecondWallet, - TwinCardsStep.CreateThirdWallet, - -> Unit - } - } - is TwinCardsAction.Wallet.LaunchFirstStep -> { - val manager = TwinCardsManager(card = getScanResponse().card) - store.dispatch(TwinCardsAction.CardsManager.Set(manager)) - - scope.launch { - when (val result = manager.createFirstWallet(action.initialMessage)) { - is CompletionResult.Success -> { - // remove wallet only after first step of retwin - scope.launch { - userWalletsListManager.delete( - listOfNotNull(UserWalletIdBuilder.scanResponse(getScanResponse()).build()), - ) - } - Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) - startCardActivation(result.data.cardId) - delay(DELAY_SDK_DIALOG_CLOSE) - withMainContext { - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateSecondWallet)) - } - } - is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error) - } - } - } - is TwinCardsAction.Wallet.LaunchSecondStep -> { - val manager = twinCardsState.twinCardsManager ?: return - - scope.launch { - val result = manager.createSecondWallet( - action.initialMessage, - action.preparingMessage, - action.creatingWalletMessage, - ) - when (result) { - is CompletionResult.Success -> { - startCardActivation(result.data.cardId) - delay(DELAY_SDK_DIALOG_CLOSE) - withMainContext { - store.dispatch(TwinCardsAction.SetPairCardId(result.data.cardId)) - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateThirdWallet)) - } - } - is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error) - } - } - } - is TwinCardsAction.Wallet.LaunchThirdStep -> { - val manager = twinCardsState.twinCardsManager ?: return - - scope.launch { - when (val result = manager.complete(action.message)) { - is CompletionResult.Success -> { - Analytics.send(Onboarding.Twins.SetupFinished()) - updateScanResponse(result.data) - - delay(DELAY_SDK_DIALOG_CLOSE) - withMainContext { - when (twinCardsState.mode) { - is CreateTwinWalletMode.CreateWallet -> { - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.TopUpWallet)) - } - is CreateTwinWalletMode.RecreateWallet -> { - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Done)) - } - } - } - } - is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error) - } - } - } - is TwinCardsAction.Balance.Update -> { - val walletManager = if (twinCardsState.walletManager != null) { - twinCardsState.walletManager - } else { - val wmFactory = runBlocking { - store.inject(DaggerGraphState::blockchainSDKFactory).getWalletManagerFactorySync() - } - val walletManager = wmFactory?.makePrimaryWalletManager(getScanResponse()).guard { - val message = "Loading cancelled. Cause: wallet manager didn't created" - val customError = TapError.CustomError(message) - store.dispatchErrorNotification(customError) - return - } - dispatch(TwinCardsAction.SetWalletManager(walletManager)) - walletManager - } - val isLoadedBefore = twinCardsState.walletBalance.state != ProgressState.Loading - val balanceIsLoading = twinCardsState.walletBalance.copy( - currency = Currency.Blockchain( - walletManager.wallet.blockchain, - walletManager.wallet.publicKey.derivationPath?.rawPath, - ), - state = ProgressState.Loading, - error = null, - criticalError = null, - ) - store.dispatch(TwinCardsAction.Balance.Set(balanceIsLoading)) - - scope.launch { - val loadedBalance = onboardingManager?.updateBalance(walletManager) ?: return@launch - loadedBalance.criticalError?.let(store::dispatchErrorNotification) - delay(if (isLoadedBefore) 0 else 300) - withMainContext { - store.dispatch(TwinCardsAction.Balance.Set(loadedBalance)) - store.dispatch(TwinCardsAction.Balance.SetCriticalError(loadedBalance.criticalError)) - store.dispatch(TwinCardsAction.Balance.SetNonCriticalError(loadedBalance.error)) - } - } - } - is TwinCardsAction.Balance.Set -> { - if (action.balance.balanceIsToppedUp()) { - OnboardingHelper.sendToppedUpEvent(getScanResponse()) - store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.Done)) - } - } - is TwinCardsAction.ShowAddressInfoDialog -> { - val addressData = twinCardsState.walletManager?.getAddressData() ?: return - - val appDialog = AppDialog.AddressInfoDialog(twinCardsState.walletBalance.currency, addressData) - store.dispatchDialogShow(appDialog) - } - is TwinCardsAction.TopUp -> { - val walletManager = twinCardsState.walletManager.guard { - store.dispatchDebugErrorNotification("NPE: WalletManager") - return - } - - OnboardingHelper.handleTopUpAction( - walletManager = walletManager, - scanResponse = onboardingManager?.scanResponse ?: return, - ) - } - TwinCardsAction.Done -> { - val scanResponse = getScanResponse() - when (twinCardsState.mode) { - is CreateTwinWalletMode.CreateWallet -> { - store.dispatchOnMain(GlobalAction.Onboarding.Stop) - OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse) - } - is CreateTwinWalletMode.RecreateWallet -> { - scope.launch { - val walletsRepository = store.inject(DaggerGraphState::walletsRepository) - - if (walletsRepository.shouldSaveUserWalletsSync()) { - OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse) - } else { - store.dispatchNavigationAction { popTo() } - } - } - } - } - } - is TwinCardsAction.SaveScannedTwinCardAndNavigateToWallet -> { - OnboardingHelper.trySaveWalletAndNavigateToWalletScreen( - scanResponse = action.scanResponse, - ) - } - is TwinCardsAction.OnBackPressed -> { - if (twinCardsState.twinningInProgress) { - store.dispatchDialogShow(OnboardingDialog.TwinningProcessNotCompleted) - } else { - val onOkCallback = { - val shouldReturnCardBack = twinCardsState.mode == CreateTwinWalletMode.CreateWallet && - twinCardsState.currentStep != TwinCardsStep.TopUpWallet && - twinCardsState.currentStep != TwinCardsStep.Done - - OnboardingHelper.onInterrupted() - store.dispatch(TwinCardsAction.CardsManager.Release) - - action.shouldResetTwinCardsWidget(shouldReturnCardBack) { - store.dispatchNavigationAction { popTo(routeClass = getPopBackScreen()) } - } - } - store.dispatchDialogShow(OnboardingDialog.InterruptOnboarding(onOkCallback)) - } - } - else -> Unit - } -} - -private fun showCardVerificationFailedDialog(error: TangemError) { - if (error is TangemSdkError.CardVerificationFailed) { - Analytics.send( - event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed( - AnalyticsParam.ScreensSources.Onboarding, - ), - ) - - val resource = error.localizedDescriptionRes() - val resId = resource.resId ?: R.string.common_unknown_error - val resArgs = resource.args.map { it.value } - - store.inject(DaggerGraphState::uiMessageSender).send( - message = Dialogs.cardVerificationFailed( - errorDescription = resourceReference(id = resId, resArgs.toWrappedList()), - onRequestSupport = { - mainScope.launch { - store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke( - type = FeedbackEmailType.CardAttestationFailed, - ) - } - }, - ), - ) - } -} - -private fun getPopBackScreen(): KClass { - val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) - - return if (userWalletsListManager.hasUserWallets) { - val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync!! }.getOrElse { false } - - if (isLocked) { - AppRoute.Welcome::class - } else { - AppRoute.Wallet::class - } - } else { - AppRoute.Home::class - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt deleted file mode 100644 index 594dd4e77c..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.tangem.tap.features.onboarding.products.twins.redux - -import com.tangem.domain.common.getTwinCardNumber -import com.tangem.domain.common.util.cardTypesResolver -import com.tangem.tap.common.redux.AppState -import org.rekotlin.Action - -object TwinCardsReducer { - fun reduce(action: Action, state: AppState): TwinCardsState = internalReduce(action, state) -} - -@Suppress("ComplexMethod") -private fun internalReduce(action: Action, state: AppState): TwinCardsState { - if (action !is TwinCardsAction) return state.twinCardsState - - var state = state.twinCardsState - - when (action) { - is TwinCardsAction.IfTwinsPrepareState -> { - state = if (action.scanResponse.cardTypesResolver.isTangemTwins()) { - val cardNumber = action.scanResponse.card.getTwinCardNumber() ?: return state - - TwinCardsState( - cardNumber = cardNumber, - mode = CreateTwinWalletMode.CreateWallet, - ) - } else { - TwinCardsState() - } - } - is TwinCardsAction.SetMode -> { - state = state.copy( - mode = action.mode, - userWasUnderstandIfWalletRecreate = false, - ) - } - is TwinCardsAction.SetStepOfScreen -> { - state = state.copy( - currentStep = action.step, - welcomeOnlyScanResponse = (action.step as? TwinCardsStep.WelcomeOnly)?.scanResponse, - ) - } - is TwinCardsAction.SetUserUnderstand -> { - state = state.copy(userWasUnderstandIfWalletRecreate = action.isUnderstand) - } - is TwinCardsAction.CardsManager.Set -> { - state = state.copy(twinCardsManager = action.manager) - } - TwinCardsAction.CardsManager.Release -> { - state = state.copy(twinCardsManager = null) - } - is TwinCardsAction.SetPairCardId -> { - state = state.copy(pairCardId = action.cardId) - } - is TwinCardsAction.SetWalletManager -> { - state = state.copy(walletManager = action.walletManager) - } - is TwinCardsAction.Balance.Set -> { - state = state.copy(walletBalance = action.balance) - } - is TwinCardsAction.Balance.SetCriticalError -> { - state = state.copy(balanceCriticalError = action.error) - } - is TwinCardsAction.Balance.SetNonCriticalError -> { - state = state.copy(balanceNonCriticalError = action.error) - } - is TwinCardsAction.Confetti.Show -> { - state = state.copy(showConfetti = true) - } - is TwinCardsAction.Confetti.Hide -> { - state = state.copy(showConfetti = false) - } - else -> {} - } - - return state -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt deleted file mode 100644 index 83e641bc8a..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.tangem.tap.features.onboarding.products.twins.redux - -import com.tangem.blockchain.common.WalletManager -import com.tangem.domain.common.TwinCardNumber -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.twins.TwinCardsManager -import com.tangem.tap.features.onboarding.OnboardingWalletBalance -import org.rekotlin.StateType - -/** -[REDACTED_AUTHOR] - */ -data class TwinCardsState( - // if cardNumber = null -> the scanned card is not Twin - val cardNumber: TwinCardNumber? = null, - val mode: CreateTwinWalletMode = CreateTwinWalletMode.CreateWallet, - val currentStep: TwinCardsStep = TwinCardsStep.Welcome, - val userWasUnderstandIfWalletRecreate: Boolean = false, - // available only when creating or recreating wallets - val twinCardsManager: TwinCardsManager? = null, - - // for the onboarding - val pairCardId: String? = null, // available after create\recreate wallets - val walletManager: WalletManager? = null, - val walletBalance: OnboardingWalletBalance = OnboardingWalletBalance.loading(), - val balanceNonCriticalError: TapError? = null, - val balanceCriticalError: TapError? = null, - val showConfetti: Boolean = false, - val welcomeOnlyScanResponse: ScanResponse? = null, -) : StateType { - - val steps: List - get() = when (mode) { - is CreateTwinWalletMode.CreateWallet -> listOf( - TwinCardsStep.None, - TwinCardsStep.CreateFirstWallet, - TwinCardsStep.CreateSecondWallet, - TwinCardsStep.CreateThirdWallet, - TwinCardsStep.TopUpWallet, - TwinCardsStep.Done, - ) - is CreateTwinWalletMode.RecreateWallet -> listOf( - TwinCardsStep.None, - TwinCardsStep.CreateFirstWallet, - TwinCardsStep.CreateSecondWallet, - TwinCardsStep.CreateThirdWallet, - TwinCardsStep.Done, - ) - } - - val progress: Int - get() = steps.indexOf(currentStep) - - val twinningInProgress: Boolean - get() = currentStep == TwinCardsStep.CreateSecondWallet || currentStep == TwinCardsStep.CreateThirdWallet -} - -sealed class CreateTwinWalletMode { - data object CreateWallet : CreateTwinWalletMode() - - data class RecreateWallet( - val scanResponse: ScanResponse, - ) : CreateTwinWalletMode() -} - -sealed class TwinCardsStep { - object None : TwinCardsStep() - data class WelcomeOnly( - val scanResponse: ScanResponse, - ) : TwinCardsStep() - - object Welcome : TwinCardsStep() - object Warning : TwinCardsStep() - object CreateFirstWallet : TwinCardsStep() - object CreateSecondWallet : TwinCardsStep() - object CreateThirdWallet : TwinCardsStep() - - // for the onboarding - object TopUpWallet : TwinCardsStep() - object Done : TwinCardsStep() -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt deleted file mode 100644 index f058c94f3b..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt +++ /dev/null @@ -1,460 +0,0 @@ -package com.tangem.tap.features.onboarding.products.twins.ui - -import android.os.Bundle -import android.util.TypedValue -import android.view.View -import android.view.animation.OvershootInterpolator -import androidx.annotation.LayoutRes -import androidx.constraintlayout.widget.ConstraintSet -import androidx.core.view.MenuProvider -import androidx.core.view.isVisible -import androidx.transition.TransitionManager -import coil.load -import com.tangem.Message -import com.tangem.blockchain.common.Blockchain -import com.tangem.common.extensions.VoidCallback -import com.tangem.core.analytics.Analytics -import com.tangem.core.navigation.ShareElement -import com.tangem.core.ui.extensions.setStatusBarColor -import com.tangem.domain.common.TwinCardNumber -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.wallets.models.Artwork -import com.tangem.sdk.ui.widget.leapfrogWidget.LeapfrogWidget -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.beginDelayedTransition -import com.tangem.tap.common.extensions.getDrawableCompat -import com.tangem.tap.common.extensions.hide -import com.tangem.tap.common.extensions.show -import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget -import com.tangem.tap.common.transitions.InternalNoteLayoutTransition -import com.tangem.tap.domain.twins.TwinsCardWidget -import com.tangem.tap.features.addBackPressHandler -import com.tangem.tap.features.onboarding.OnboardingMenuProvider -import com.tangem.tap.features.onboarding.OnboardingWalletBalance -import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment -import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState -import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep -import com.tangem.tap.store -import com.tangem.utils.Provider -import com.tangem.utils.extensions.stripZeroPlainString -import com.tangem.wallet.R -import com.tangem.wallet.databinding.LayoutOnboardingContainerTopBinding -import dagger.hilt.android.AndroidEntryPoint - -@Suppress("LargeClass") -@AndroidEntryPoint -internal class OnboardingTwinsFragment : BaseOnboardingFragment() { - - private val mainBinding by lazy { binding.vMain } - private var previousStep: TwinCardsStep = TwinCardsStep.None - - private lateinit var twinsWidget: TwinsCardWidget - private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - store.dispatch(TwinCardsAction.Init) - } - - override fun configureTransitions() { - when (store.state.twinCardsState.mode) { - is CreateTwinWalletMode.CreateWallet -> { - super.configureTransitions() - } - is CreateTwinWalletMode.RecreateWallet -> { - configureDefaultTransactions() - } - } - } - - override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider( - scanResponseProvider = Provider { getActualScanResponse() }, - ) - - @Suppress("MagicNumber") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - addBackPressHandler(this) - - reconfigureLayoutForTwins(mainBinding.onboardingTopContainer) - - val typedValue = TypedValue() - resources.getValue(R.dimen.device_scale_factor_for_twins_welcome, typedValue, true) - val deviceScaleFactorForWelcomeState = typedValue.float - - twinsWidget = TwinsCardWidget( - LeapfrogWidget(mainBinding.onboardingTopContainer.cardsContainer), - deviceScaleFactorForWelcomeState, - ) { - 285f * deviceScaleFactorForWelcomeState - } - btnRefreshBalanceWidget = - RefreshBalanceWidget(mainBinding.onboardingTopContainer.onboardingWalletContainer) - - binding.toolbar.title = getText(R.string.twins_recreate_toolbar) - - mainBinding.onboardingTopContainer.imvTwinFrontCard.load(Artwork.TWIN_CARD_1_URL) { - placeholder(R.drawable.card_placeholder_black) - error(R.drawable.card_placeholder_black) - fallback(R.drawable.card_placeholder_black) - } - - mainBinding.onboardingTopContainer.imvTwinBackCard.load(Artwork.TWIN_CARD_2_URL) { - placeholder(R.drawable.card_placeholder_white) - error(R.drawable.card_placeholder_white) - fallback(R.drawable.card_placeholder_white) - } - } - - override fun onStart() { - super.onStart() - setStatusBarColor(R.color.background_primary) - } - - private fun reconfigureLayoutForTwins(containerBinding: LayoutOnboardingContainerTopBinding) = - with(containerBinding) { - imvFrontCard.hide() - imvCardBackground.hide() - cardsContainer.show() - - imvTwinFrontCard.transitionName = ShareElement.imvFrontCard - imvTwinBackCard.transitionName = ShareElement.imvBackCard - - // if don't this, the bg_circle_... is overflow the app_bar - binding.appBar.bringToFront() - } - - override fun subscribeToStore() { - store.subscribe(this) { state -> - state.skipRepeats { oldState, newState -> - oldState.twinCardsState == newState.twinCardsState - }.select { it.twinCardsState } - } - storeSubscribersList.add(this) - } - - override fun newState(state: TwinCardsState) { - if (activity == null || view == null) return - - pbBinding.pbState.max = state.steps.size - 1 - pbBinding.pbState.progress = state.progress - - when (state.currentStep) { - is TwinCardsStep.WelcomeOnly -> setupWelcomeOnlyState(state, state.currentStep.scanResponse) - is TwinCardsStep.Welcome -> setupWelcomeState(state) - is TwinCardsStep.Warning -> setupWarningState(state) - is TwinCardsStep.CreateFirstWallet -> setupCreateFirstWalletState(state) - is TwinCardsStep.CreateSecondWallet -> setupCreateSecondWalletState(state) - is TwinCardsStep.CreateThirdWallet -> setupCreateThirdWalletState(state) - is TwinCardsStep.TopUpWallet -> setupTopUpWalletState(state) - is TwinCardsStep.Done -> setupDoneState(state) - else -> {} - } - - setBalance(state) - showConfetti(state.showConfetti) - previousStep = state.currentStep - } - - private fun setBalance(state: TwinCardsState) { - if (state.walletBalance.currency.blockchain == Blockchain.Unknown) return - - with(mainBinding.onboardingTopContainer.onboardingTvBalance) { - if (state.balanceCriticalError == null) { - val balanceValue = state.walletBalance.value.stripZeroPlainString() - tvBalanceValue.text = balanceValue - tvBalanceCurrency.text = state.walletBalance.currency.currencySymbol - } else { - tvBalanceValue.text = "–" - tvBalanceCurrency.text = "" - } - } - } - - private fun setupWelcomeOnlyState(state: TwinCardsState, scanResponse: ScanResponse) { - setupWelcomeState(state) { - store.dispatch(TwinCardsAction.SaveScannedTwinCardAndNavigateToWallet(scanResponse)) - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.None)) - } - } - - private fun setupWelcomeState(state: TwinCardsState) { - setupWelcomeState(state) { - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) - } - } - - private fun setupWelcomeState(state: TwinCardsState, onMainButtonClick: VoidCallback) = - with(mainBinding.onboardingActionContainer) { - twinsWidget.toWelcome(false) - - mainBinding.onboardingTopContainer.onboardingTwinsWelcomeBg.root.show() - pbBinding.pbState.hide() - - tvHeader.setText(R.string.twins_onboarding_subtitle) - tvBody.text = getString( - R.string.twins_onboarding_description_format, - state.cardNumber?.pairIndexNumber(), - ) - - btnMainAction.setText(R.string.common_continue) - btnMainAction.icon = null - btnMainAction.setOnClickListener { onMainButtonClick() } - } - - private fun setupWarningState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { - twinsWidget.toWelcome(false) - - mainBinding.onboardingTopContainer.onboardingTwinsWelcomeBg.root.hide() - pbBinding.pbState.hide() - chbUnderstand.show() - - tvHeader.setText(R.string.common_warning) - tvBody.setText(R.string.twins_recreate_warning) - - chbUnderstand.setOnCheckedChangeListener { _, isChecked -> - store.dispatch(TwinCardsAction.SetUserUnderstand(isChecked)) - } - btnMainAction.isEnabled = state.userWasUnderstandIfWalletRecreate - btnMainAction.setText(R.string.common_continue) - btnMainAction.icon = null - btnMainAction.setOnClickListener { - store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) - } - } - - private fun setupCreateFirstWalletState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { - mainBinding.onboardingTopContainer.onboardingTwinsWelcomeBg.root.hide() - mainBinding.onboardingTopContainer.onboardingTwinsWelcomeBg.bgCircleLarge.hide() - mainBinding.onboardingTopContainer.onboardingTwinsWelcomeBg.bgCircleMedium.hide() - mainBinding.onboardingTopContainer.onboardingTwinsWelcomeBg.bgCircleMin.hide() - chbUnderstand.hide() - pbBinding.pbState.show() - - mainBinding.onboardingTopContainer.onboardingWalletContainer.beginDelayedTransition() - - when (previousStep) { - TwinCardsStep.None -> { - twinsWidget.toLeapfrog(false) { - when (state.cardNumber) { - TwinCardNumber.First -> {} - TwinCardNumber.Second -> { - switchToCard( - state.cardNumber, - false, - ) - } - else -> {} - } - } - } - TwinCardsStep.Welcome, TwinCardsStep.Warning -> { - twinsWidget.toLeapfrog(onEnd = { switchToCard(state.cardNumber) }) - } - else -> {} - } - - val twinIndexNumber = state.cardNumber?.indexNumber() - tvHeader.text = getString(R.string.twins_recreate_title_format, twinIndexNumber) - tvBody.setText(R.string.onboarding_twins_interrupt_warning) - - btnMainAction.text = getString(R.string.twins_recreate_button_format, twinIndexNumber) - btnMainAction.setIconResource(R.drawable.ic_tangem_24) - btnMainAction.setOnClickListener { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) - store.dispatch( - TwinCardsAction.Wallet.LaunchFirstStep( - initialMessage = Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)), - ), - ) - } - - btnAlternativeAction.isVisible = false - btnAlternativeAction.isClickable = false - } - - private fun setupCreateSecondWalletState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { - switchToCard(state.cardNumber?.pairNumber()) - - val twinPairIndexNumber = state.cardNumber?.pairIndexNumber() - tvHeader.text = getString(R.string.twins_recreate_title_format, twinPairIndexNumber) - tvBody.setText(R.string.onboarding_twins_interrupt_warning) - - btnMainAction.text = - getString(R.string.twins_recreate_button_format, twinPairIndexNumber) - btnMainAction.setIconResource(R.drawable.ic_tangem_24) - btnMainAction.setOnClickListener { - store.dispatch( - TwinCardsAction.Wallet.LaunchSecondStep( - Message( - getString( - R.string.twins_recreate_title_format, - twinPairIndexNumber, - ), - ), - Message(getString(R.string.twins_recreate_title_preparing)), - Message(getString(R.string.twins_recreate_title_creating_wallet)), - ), - ) - } - } - - private fun setupCreateThirdWalletState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { - switchToCard(state.cardNumber) - - val twinIndexNumber = state.cardNumber?.indexNumber() - tvHeader.text = getString(R.string.twins_recreate_title_format, twinIndexNumber) - tvBody.setText(R.string.onboarding_twins_interrupt_warning) - - btnMainAction.text = getString(R.string.twins_recreate_button_format, twinIndexNumber) - btnMainAction.setIconResource(R.drawable.ic_tangem_24) - btnMainAction.setOnClickListener { - store.dispatch( - TwinCardsAction.Wallet.LaunchThirdStep( - Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)), - ), - ) - } - } - - private fun setupTopUpWalletState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { - when (previousStep) { - TwinCardsStep.None, TwinCardsStep.Welcome -> { - when (state.cardNumber) { - TwinCardNumber.First -> { - twinsWidget.leapfrogWidget.unfold(true) { - twinsWidget.toActivate(true) - } - } - TwinCardNumber.Second -> { - switchToCard(state.cardNumber, true) { - twinsWidget.toActivate(true) - } - } - else -> {} - } - } - TwinCardsStep.CreateThirdWallet -> { - twinsWidget.toActivate() - } - else -> {} - } - - if (availableForBuy(getActualScanResponse(), state.walletBalance)) { - btnMainAction.setText(R.string.onboarding_top_up_button_but_crypto) - btnMainAction.setOnClickListener { - store.dispatch(TwinCardsAction.TopUp) - } - btnAlternativeAction.isVisible = true - btnAlternativeAction.setText(R.string.onboarding_top_up_button_show_wallet_address) - btnAlternativeAction.setOnClickListener { - store.dispatch(TwinCardsAction.ShowAddressInfoDialog) - } - } else { - btnMainAction.setText(R.string.onboarding_button_receive_crypto) - btnMainAction.setOnClickListener { - store.dispatch(TwinCardsAction.ShowAddressInfoDialog) - } - - btnAlternativeAction.isVisible = false - } - - tvHeader.setText(R.string.onboarding_topup_title) - tvBody.setText(R.string.onboarding_top_up_body) - btnMainAction.icon = null - - btnRefreshBalanceWidget.changeState(state.walletBalance.state) - if (btnRefreshBalanceWidget.isShowing != true) { - btnRefreshBalanceWidget.mainView.setOnClickListener { - store.dispatch(TwinCardsAction.Balance.Update) - } - } - mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable( - requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8), - ) - mainBinding.onboardingTopContainer.imvCardBackground.backgroundTintList = - requireContext().resources.getColorStateList(R.color.onboarding_card_background, null) - - updateConstraints(state.currentStep, R.layout.lp_onboarding_topup_wallet_twins) - } - - private fun setupDoneState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { - btnMainAction.setText(R.string.common_continue) - btnMainAction.icon = null - btnMainAction.setOnClickListener { - store.dispatch(TwinCardsAction.Confetti.Hide) - store.dispatch(TwinCardsAction.Done) - } - - btnAlternativeAction.isVisible = false - btnAlternativeAction.isClickable = false - - tvHeader.setText(R.string.onboarding_done_header) - tvBody.setText(R.string.onboarding_done_body) - - val layout = when (state.mode) { - is CreateTwinWalletMode.CreateWallet -> R.layout.lp_onboarding_done_activation_twins - is CreateTwinWalletMode.RecreateWallet -> R.layout.lp_onboarding_done - } - updateConstraints(state.currentStep, layout) - } - - private fun updateConstraints(currentStep: TwinCardsStep, @LayoutRes layoutId: Int) { - if (this.previousStep == currentStep) return - - with(mainBinding.onboardingTopContainer) { - val constraintSet = ConstraintSet() - constraintSet.clone(requireContext(), layoutId) - constraintSet.applyTo(onboardingWalletContainer) - val transition = InternalNoteLayoutTransition() - transition.interpolator = OvershootInterpolator() - TransitionManager.beginDelayedTransition(onboardingWalletContainer, transition) - } - } - - private fun switchToCard(cardNumber: TwinCardNumber?, animate: Boolean = true, onEnd: VoidCallback = {}) { - val position = cardNumber?.number ?: return - - if (twinsWidget.leapfrogWidget.getViewPositionByIndex(1) != position - 1) { - twinsWidget.leapfrogWidget.leap(animate, onEnd) - } else { - onEnd() - } - } - - private fun availableForBuy(scanResponse: ScanResponse?, walletBalance: OnboardingWalletBalance): Boolean { - scanResponse ?: return false - return store.state.globalState.exchangeManager.availableForBuy(scanResponse, walletBalance.currency) - } - - private fun getActualScanResponse(): ScanResponse { - return store.state.twinCardsState.welcomeOnlyScanResponse - ?: store.state.globalState.onboardingState.onboardingManager?.scanResponse - ?: store.state.detailsState.scanResponse - ?: error("ScanResponse must be not null") - } - - override fun handleOnBackPressed() { - store.dispatch( - TwinCardsAction.OnBackPressed { should, popAction -> - store.dispatch(TwinCardsAction.Confetti.Hide) - showConfetti(false) - if (should) { - switchToCard(TwinCardNumber.First, true, popAction) - } else { - popAction() - } - }, - ) - } -} - -private fun TwinCardNumber?.indexNumber(): String { - return this?.number?.toString() ?: "" -} - -private fun TwinCardNumber?.pairIndexNumber(): String { - return this?.pairNumber()?.number?.toString() ?: "" -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/TwinningProcessNotCompletedDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/TwinningProcessNotCompletedDialog.kt deleted file mode 100644 index 60faf916d7..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/TwinningProcessNotCompletedDialog.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.tap.features.onboarding.products.twins.ui.dialog - -import android.content.Context -import androidx.appcompat.app.AlertDialog -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.tangem.tap.common.extensions.dispatchDialogHide -import com.tangem.tap.store -import com.tangem.wallet.R - -/** -[REDACTED_AUTHOR] - */ -object TwinningProcessNotCompletedDialog { - fun create(context: Context): AlertDialog { - return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog) - .setMessage(R.string.onboarding_twin_exit_warning) - .setPositiveButton(R.string.warning_button_ok) { _, _ -> } - .setOnDismissListener { store.dispatchDialogHide() } - .create() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupDialog.kt new file mode 100644 index 0000000000..ef465fad15 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupDialog.kt @@ -0,0 +1,14 @@ +package com.tangem.tap.features.onboarding.products.wallet.redux + +import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.redux.StateDialog + +sealed class BackupDialog : StateDialog { + data class UnfinishedBackupFound( + val scanResponse: ScanResponse? = null, + ) : BackupDialog() + + data class ConfirmDiscardingBackup( + val scanResponse: ScanResponse? = null, + ) : BackupDialog() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupMiddleware.kt new file mode 100644 index 0000000000..c3567c8f3a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/BackupMiddleware.kt @@ -0,0 +1,59 @@ +package com.tangem.tap.features.onboarding.products.wallet.redux + +import com.tangem.common.routing.AppRoute +import com.tangem.core.analytics.Analytics +import com.tangem.tap.* +import com.tangem.tap.common.analytics.events.Onboarding.* +import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.features.demo.DemoHelper +import com.tangem.tap.proxy.redux.DaggerGraphState +import kotlinx.coroutines.launch +import org.rekotlin.Middleware + +class BackupMiddleware { + val backupMiddleware: Middleware = { dispatch, state -> + { next -> + { action -> + if (action is BackupAction) handleBackupAction(state, action) + next(action) + } + } + } +} + +@Suppress("LongMethod", "ComplexMethod", "MagicNumber") +private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) { + if (DemoHelper.tryHandle(appState, action)) return + + when (action) { + is BackupAction.DiscardBackup -> { + backupService.discardSavedBackup() + } + is BackupAction.DiscardSavedBackup -> { + mainScope.launch { + backupService.discardSavedBackup() + + val onboardingRepository = store.inject(DaggerGraphState::onboardingRepository) + val cardRepository = store.inject(DaggerGraphState::cardRepository) + val unfinishedBackup = onboardingRepository.getUnfinishedFinalizeOnboarding() ?: return@launch + + cardRepository.finishCardActivation(unfinishedBackup.card.cardId) + onboardingRepository.clearUnfinishedFinalizeOnboarding() + Analytics.send(Finished()) + } + } + is BackupAction.ResumeFoundUnfinishedBackup -> { + if (action.unfinishedBackupScanResponse != null) { + store.dispatchNavigationAction { + push( + AppRoute.Onboarding( + scanResponse = action.unfinishedBackupScanResponse, + mode = AppRoute.Onboarding.Mode.ContinueFinalize, + ), + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt index a4be295931..bf97ad0ae2 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt @@ -1,108 +1,19 @@ package com.tangem.tap.features.onboarding.products.wallet.redux -import android.net.Uri -import com.tangem.common.CompletionResult -import com.tangem.common.card.Card import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.feature.onboarding.data.model.CreateWalletResponse -import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource -import com.tangem.sdk.api.CreateProductWalletTaskResponse -import kotlinx.coroutines.CoroutineScope import org.rekotlin.Action sealed class OnboardingWalletAction : Action { - data object Init : OnboardingWalletAction() - data object GetToCreateWalletStep : OnboardingWalletAction() - data object CreateWallet : OnboardingWalletAction() - data class WalletWasCreated( - val shouldSendAnalyticsEvent: Boolean, - val result: CompletionResult, - ) : OnboardingWalletAction() - - data object Done : OnboardingWalletAction() - data class FinishOnboarding(val scope: CoroutineScope) : OnboardingWalletAction() - - data object ResumeBackup : OnboardingWalletAction() - - data class LoadArtwork(val cardArtworkUriForUnfinishedBackup: Uri? = null) : OnboardingWalletAction() - class SetPrimaryCardArtworkUrl(val artworkUri: Uri?) : OnboardingWalletAction() - class SetSecondCardArtworkUrl(val artworkUri: Uri?) : OnboardingWalletAction() - class SetThirdCardArtworkUrl(val artworkUri: Uri?) : OnboardingWalletAction() - - data object OnBackPressed : OnboardingWalletAction() - data class WalletSaved(val userWalletId: UserWalletId) : OnboardingWalletAction() } -sealed class OnboardingWallet2Action : OnboardingWalletAction() { - data class Init(val maxProgress: Int) : OnboardingWallet2Action() - data class SetDependencies(val maxProgress: Int) : OnboardingWallet2Action() - - data class CreateWallet( - val callback: (CompletionResult) -> Unit, - ) : OnboardingWallet2Action() - - data class ImportWallet( - val mnemonicComponents: List, - val passphrase: String?, - val seedPhraseSource: SeedPhraseSource, - val callback: (CompletionResult) -> Unit, - ) : OnboardingWallet2Action() - - data class WalletWasCreated( - val result: CompletionResult, - ) : OnboardingWallet2Action() -} - sealed class BackupAction : Action { - data object IntroduceBackup : BackupAction() - data object StartBackup : BackupAction() - data object SkipBackup : BackupAction() - - data object ErrorInBackupCard : BackupAction() - data object StartAddingPrimaryCard : BackupAction() - data object ScanPrimaryCard : BackupAction() - data class SetHasRing(val hasRing: Boolean) : BackupAction() - - /** - * Check for unfinished backup of standard Wallets - * See more GlobalAction.Onboarding.StartForUnfinishedBackup - */ - data object CheckForUnfinishedBackup : BackupAction() - - data object StartAddingBackupCards : BackupAction() - data object AddBackupCard : BackupAction() { - data class Success(val card: Card) : BackupAction() - data class ChangeButtonLoading(val isLoading: Boolean) : BackupAction() - } - - data object FinishAddingBackupCards : BackupAction() - - data object ShowAccessCodeInfoScreen : BackupAction() - data object ShowEnterAccessCodeScreen : BackupAction() - data class CheckAccessCode(val accessCode: String) : BackupAction() - data class SetAccessCodeError(val error: AccessCodeError?) : BackupAction() - data class SaveFirstAccessCode(val accessCode: String) : BackupAction() - data class SaveAccessCodeConfirmation(val accessCodeConfirmation: String) : BackupAction() - data object OnAccessCodeDialogClosed : BackupAction() - - data object PrepareToWritePrimaryCard : BackupAction() - data object WritePrimaryCard : BackupAction() - data class PrepareToWriteBackupCard(val cardNumber: Int) : BackupAction() - data class WriteBackupCard(val cardNumber: Int) : BackupAction() - - data class FinishBackup(val withAnalytics: Boolean = true) : BackupAction() - - data class BackupFinished(val userWalletId: UserWalletId?) : BackupAction() - data object DiscardBackup : BackupAction() data object DiscardSavedBackup : BackupAction() data class ResumeFoundUnfinishedBackup( val unfinishedBackupScanResponse: ScanResponse?, ) : BackupAction() - - data class ResetBackupCard(val cardId: String) : BackupAction() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt deleted file mode 100644 index fe64265670..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ /dev/null @@ -1,849 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.redux - -import android.net.Uri -import com.tangem.common.CompletionResult -import com.tangem.common.card.Card -import com.tangem.common.core.TangemSdkError -import com.tangem.common.extensions.ifNotNull -import com.tangem.common.extensions.toHexString -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.AppRouter -import com.tangem.common.services.Result -import com.tangem.core.analytics.Analytics -import com.tangem.core.analytics.models.AnalyticsParam.ScreensSources -import com.tangem.core.analytics.models.ExceptionAnalyticsEvent -import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.toWrappedList -import com.tangem.core.ui.message.dialog.Dialogs -import com.tangem.domain.common.extensions.withIOContext -import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.common.util.cardTypesResolver -import com.tangem.domain.feedback.models.FeedbackEmailType -import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_IDS -import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_PREFIX -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.wallets.builder.UserWalletIdBuilder -import com.tangem.domain.wallets.legacy.UserWalletsListManager -import com.tangem.domain.wallets.models.Artwork -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.feature.onboarding.data.model.CreateWalletResponse -import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource -import com.tangem.feature.wallet.presentation.wallet.domain.BackupValidator -import com.tangem.operations.attestation.CardArtworksProvider -import com.tangem.operations.backup.BackupService -import com.tangem.sdk.api.CreateProductWalletTaskResponse -import com.tangem.sdk.extensions.localizedDescriptionRes -import com.tangem.tap.* -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.* -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.features.demo.DemoHelper -import com.tangem.tap.features.onboarding.OnboardingDialog -import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.wallet.R -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.rekotlin.Action -import org.rekotlin.Middleware - -object OnboardingWalletMiddleware { - val handler = onboardingWalletMiddleware -} - -private const val HIDE_PROGRESS_DELAY = 400L - -private val onboardingWalletMiddleware: Middleware = { dispatch, state -> - { next -> - { action -> - when (action) { - is OnboardingWallet2Action -> handleWallet2Action(action) - else -> handleWalletAction(action) - } - next(action) - } - } -} - -@Suppress("LongMethod", "ComplexMethod") -private fun handleWalletAction(action: Action) { - if (action !is OnboardingWalletAction) return - - val globalState = store.state.globalState - val onboardingManager = globalState.onboardingState.onboardingManager - - val scanResponse = onboardingManager?.scanResponse - val card = scanResponse?.card - - val onboardingWalletState = store.state.onboardingWalletState - - when (action) { - OnboardingWalletAction.Init -> { - ifNotNull(onboardingManager, card) { manager, notNullCard -> - mainScope.launch { - if (!manager.isActivationStarted(notNullCard.cardId)) { - Analytics.send(Onboarding.Started()) - } - } - } - when { - card == null -> { - // it's possible when found unfinished backup - store.dispatch(OnboardingWalletAction.ResumeBackup) - } - card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup -> { - store.dispatch(OnboardingWalletAction.ResumeBackup) - } - card.wallets.isNotEmpty() && card.backupStatus?.isActive == true -> { - store.dispatch(BackupAction.FinishBackup()) - } - else -> { - store.dispatch(OnboardingWalletAction.GetToCreateWalletStep) - Analytics.send(Onboarding.CreateWallet.ScreenOpened()) - } - } - } - is OnboardingWalletAction.LoadArtwork -> { - scope.launch { - val cardArtwork = when (onboardingManager) { - null -> { - // onboardingManager is null when backup started from previously interrupted - val primaryCardId = backupService.primaryCardId - val cardPublicKey = backupService.primaryPublicKey - if (primaryCardId != null && cardPublicKey != null) { - // uses when no scanResponse and backup state restored - loadArtworkForCard( - cardId = primaryCardId, - cardPublicKey = cardPublicKey, - defaultArtwork = action.cardArtworkUriForUnfinishedBackup, - ) - } else { - action.cardArtworkUriForUnfinishedBackup - } - } - else -> onboardingManager.loadArtworkUrl() - .takeIf { it != Artwork.DEFAULT_IMG_URL } - ?.let { Uri.parse(it) } - } - store.dispatchOnMain(OnboardingWalletAction.SetPrimaryCardArtworkUrl(cardArtwork)) - } - } - is OnboardingWalletAction.CreateWallet -> { - scanResponse ?: return - scope.launch { - val result = tangemSdkManager.createProductWallet( - scanResponse, - globalState.onboardingState.shouldResetOnCreate, - ) - store.dispatchOnMain(OnboardingWalletAction.WalletWasCreated(true, result)) - } - } - is OnboardingWalletAction.WalletWasCreated -> { - scanResponse ?: return - when (val result = action.result) { - is CompletionResult.Success -> { - if (action.shouldSendAnalyticsEvent) { - Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) - } - // here we must use updated scanResponse after createWallet & derivation - val updatedResponse = globalState.onboardingState.onboardingManager.scanResponse.copy( - card = result.data.card, - derivedKeys = result.data.derivedKeys, - primaryCard = result.data.primaryCard, - ) - onboardingManager.scanResponse = updatedResponse - - store.dispatch(GlobalAction.Onboarding.ShouldResetCardOnCreate(false)) - mainScope.launch { - onboardingManager.startActivation(updatedResponse.card.cardId) - store.dispatchWithMain(OnboardingWalletAction.ResumeBackup) - } - } - is CompletionResult.Failure -> { - if (result.error is TangemSdkError.WalletAlreadyCreated) { - handleActivationError() - } - } - } - } - is OnboardingWalletAction.FinishOnboarding -> { - store.dispatch(GlobalAction.Onboarding.Stop) - navigateToWalletScreen() - store.dispatch(BackupAction.DiscardBackup) - } - is OnboardingWalletAction.ResumeBackup -> { - val newAction = when (val backupState = backupService.currentState) { - BackupService.State.FinalizingPrimaryCard -> BackupAction.PrepareToWritePrimaryCard - is BackupService.State.FinalizingBackupCard -> BackupAction.PrepareToWriteBackupCard(backupState.index) - else -> { - if (onboardingWalletState.backupState.backupStep == null || - onboardingWalletState.backupState.backupStep == BackupStep.InitBackup || - onboardingWalletState.backupState.backupStep == BackupStep.Finished - ) { - Analytics.send(Onboarding.Backup.ScreenOpened()) - - val isWallet2 = scanResponse?.cardTypesResolver?.isWallet2() ?: false - if (isWallet2) BackupAction.StartBackup else BackupAction.IntroduceBackup - } else { - null - } - } - } - newAction?.let { store.dispatch(it) } - } - OnboardingWalletAction.OnBackPressed -> handleOnBackPressed(onboardingWalletState) - else -> Unit - } -} - -private suspend fun handleFinishBackup(scanResponse: ScanResponse, userWallet: UserWallet? = null) { - val backupState = store.state.onboardingWalletState.backupState - val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState) - - val userWalletId = userWallet?.walletId ?: UserWalletIdBuilder.scanResponse(scanResponse).build() - if (backupState.hasRing && userWalletId != null) { - scope.launch { - store.inject(DaggerGraphState::walletsRepository).setHasWalletsWithRing(userWalletId = userWalletId) - } - } - - OnboardingHelper.saveWallet( - alreadyCreatedWallet = userWallet, - scanResponse = updatedScanResponse, - accessCode = backupState.accessCode, - backupCardsIds = backupState.backupCardIds, - hasBackupError = backupState.hasBackupError, - ) -} - -private fun navigateToWalletScreen() { - mainScope.launch { - val settingsRepository = store.inject(DaggerGraphState::settingsRepository) - store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) } - if (tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen()) { - delay(timeMillis = 1_800) - store.dispatchNavigationAction { push(AppRoute.SaveWallet) } - } - } -} - -private suspend fun readCard(): CompletionResult { - val shouldSaveAccessCodes = store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes() - - store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy( - isBiometricsRequestPolicy = shouldSaveAccessCodes, - ) - - return store.inject(DaggerGraphState::scanCardProcessor).scan(analyticsSource = ScreensSources.Intro) -} - -private suspend fun loadArtworkForCard(cardId: String, cardPublicKey: ByteArray, defaultArtwork: Uri?): Uri { - val onlineCardVerifier = store.inject(DaggerGraphState::onlineCardVerifier) - - return when (val cardInfo = onlineCardVerifier.getCardInfo(cardId, cardPublicKey)) { - is Result.Success -> { - val artworkId = cardInfo.data.artwork?.id - if (artworkId.isNullOrEmpty()) { - defaultArtwork ?: Uri.EMPTY - } else { - Uri.parse(CardArtworksProvider.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId)) - } - } - is Result.Failure -> defaultArtwork ?: Uri.EMPTY - } -} - -@Suppress("LongMethod", "ComplexMethod") -private fun handleWallet2Action(action: OnboardingWallet2Action) { - val globalState = store.state.globalState - val onboardingManager = globalState.onboardingState.onboardingManager - - val scanResponse = onboardingManager?.scanResponse - - when (action) { - is OnboardingWallet2Action.Init -> { - if (scanResponse?.cardTypesResolver?.isWallet2() == true) { - store.dispatch(OnboardingWallet2Action.SetDependencies(action.maxProgress)) - } - } - - is OnboardingWallet2Action.CreateWallet -> { - scanResponse ?: return - scope.launch { - val mediateResult = when ( - val result = tangemSdkManager.createProductWallet( - scanResponse, - globalState.onboardingState.shouldResetOnCreate, - ) - ) { - is CompletionResult.Success -> { - Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) - store.dispatch(GlobalAction.Onboarding.ShouldResetCardOnCreate(false)) - val response = CreateWalletResponse( - card = result.data.card, - derivedKeys = result.data.derivedKeys, - primaryCard = result.data.primaryCard, - ) - CompletionResult.Success(response) - } - - is CompletionResult.Failure -> { - if (result.error is TangemSdkError.WalletAlreadyCreated) { - handleActivationError() - } - CompletionResult.Failure(result.error) - } - } - withMainContext { - action.callback(mediateResult) - } - } - } - - is OnboardingWallet2Action.ImportWallet -> { - scanResponse ?: return - scope.launch { - val mediateResult = when ( - val result = tangemSdkManager.importWallet( - scanResponse = scanResponse, - passphrase = action.passphrase, - mnemonic = action.mnemonicComponents.joinToString(" "), - shouldReset = globalState.onboardingState.shouldResetOnCreate, - ) - ) { - is CompletionResult.Success -> { - val creationType = when (action.seedPhraseSource) { - SeedPhraseSource.IMPORTED -> AnalyticsParam.WalletCreationType.SeedImport - SeedPhraseSource.GENERATED -> AnalyticsParam.WalletCreationType.NewSeed - } - Analytics.send( - event = Onboarding.CreateWallet.WalletCreatedSuccessfully( - creationType = creationType, - seedPhraseLength = action.mnemonicComponents.size, - ), - ) - store.dispatch(GlobalAction.Onboarding.ShouldResetCardOnCreate(false)) - val response = CreateWalletResponse( - card = result.data.card, - derivedKeys = result.data.derivedKeys, - primaryCard = result.data.primaryCard, - ) - CompletionResult.Success(response) - } - - is CompletionResult.Failure -> { - if (result.error is TangemSdkError.WalletAlreadyCreated) { - handleActivationError() - } - CompletionResult.Failure(result.error) - } - } - withMainContext { - action.callback(mediateResult) - } - } - } - - is OnboardingWallet2Action.WalletWasCreated -> { - val result = when (val mediateResult = action.result) { - is CompletionResult.Success -> { - val response = CreateProductWalletTaskResponse( - card = mediateResult.data.card, - derivedKeys = mediateResult.data.derivedKeys, - primaryCard = mediateResult.data.primaryCard, - ) - CompletionResult.Success(response) - } - - is CompletionResult.Failure -> { - CompletionResult.Failure(mediateResult.error) - } - } - // do not send analytics event for wallet2 flow, cause its already sent - store.dispatchOnMain(OnboardingWalletAction.WalletWasCreated(false, result)) - } - - else -> Unit - } -} - -private fun handleActivationError() { - store.dispatchDialogShow( - OnboardingDialog.WalletActivationError( - onConfirm = { - store.dispatch(GlobalAction.Onboarding.ShouldResetCardOnCreate(true)) - }, - ), - ) -} - -private fun updateScanResponseAfterBackup(scanResponse: ScanResponse, backupState: BackupState): ScanResponse { - val card = if (backupState.backupCardsNumber > 0) { - val cardsCount = backupState.backupCardsNumber - scanResponse.card.copy( - backupStatus = CardDTO.BackupStatus.Active(cardCount = cardsCount), - isAccessCodeSet = true, - ) - } else { - scanResponse.card - } - return scanResponse.copy(card = card) -} - -class BackupMiddleware { - val backupMiddleware: Middleware = { dispatch, state -> - { next -> - { action -> - if (action is BackupAction) handleBackupAction(state, action) - next(action) - } - } - } -} - -@Suppress("LongMethod", "ComplexMethod", "MagicNumber") -private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) { - if (DemoHelper.tryHandle(appState, action)) return - val globalState = appState()?.globalState ?: return - val onboardingWalletState = appState()?.onboardingWalletState ?: return - - val backupState = onboardingWalletState.backupState - var scanResponse = globalState.onboardingState.onboardingManager?.scanResponse - val card = scanResponse?.card - - when (action) { - is BackupAction.StartBackup -> { - Analytics.send(Onboarding.Backup.Started()) - backupService.discardSavedBackup() - val primaryCard = scanResponse?.primaryCard - if (primaryCard != null) { - backupService.setPrimaryCard(primaryCard) - store.dispatch(BackupAction.StartAddingBackupCards) - } else { - store.dispatch(BackupAction.StartAddingPrimaryCard) - } - } - is BackupAction.ScanPrimaryCard -> { - val iconScanRes = if (scanResponse?.cardTypesResolver?.isRing() == true) { - R.drawable.img_hand_scan_ring - } else { - null - } - backupService.readPrimaryCard(iconScanRes = iconScanRes, cardId = card?.cardId) { result -> - when (result) { - is CompletionResult.Success -> { - store.dispatchOnMain(BackupAction.StartAddingBackupCards) - } - is CompletionResult.Failure -> Unit - } - } - } - is BackupAction.AddBackupCard -> { - store.dispatchOnMain(BackupAction.AddBackupCard.ChangeButtonLoading(true)) - backupService.addBackupCard { result -> - backupService.skipCompatibilityChecks = false - store.inject(DaggerGraphState::cardSdkConfigRepository).sdk.config.filter.cardIdFilter = null - store.dispatchOnMain(BackupAction.AddBackupCard.ChangeButtonLoading(false)) - when (result) { - is CompletionResult.Success -> { - updateArtworks(backupService.addedBackupCardsCount, result.data) - store.dispatchOnMain(BackupAction.AddBackupCard.Success(result.data)) - } - is CompletionResult.Failure -> { - when (val error = result.error) { - is TangemSdkError.CardVerificationFailed -> { - Analytics.send( - event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed( - ScreensSources.Backup, - ), - ) - - val resource = error.localizedDescriptionRes() - val resId = resource.resId ?: com.tangem.core.ui.R.string.common_unknown_error - val resArgs = resource.args.map { it.value } - - store.inject(DaggerGraphState::uiMessageSender).send( - message = Dialogs.cardVerificationFailed( - errorDescription = resourceReference(id = resId, resArgs.toWrappedList()), - onRequestSupport = { - mainScope.launch { - store.inject(DaggerGraphState::sendFeedbackEmailUseCase) - .invoke(type = FeedbackEmailType.CardAttestationFailed) - } - }, - ), - ) - } - is TangemSdkError.BackupFailedNotEmptyWallets -> { - store.dispatchOnMain( - GlobalAction.ShowDialog( - BackupDialog.ResetBackupCard(error.cardId), - ), - ) - } - is TangemSdkError.IssuerSignatureLoadingFailed -> { - store.dispatchOnMain( - GlobalAction.ShowDialog(BackupDialog.AttestationFailed), - ) - } - else -> Analytics.sendException(ExceptionAnalyticsEvent(error)) - } - } - } - } - } - is BackupAction.FinishAddingBackupCards -> { - if (backupService.addedBackupCardsCount == backupState.maxBackupCards) { - store.dispatchOnMain(BackupAction.ShowAccessCodeInfoScreen) - } else { - store.dispatchOnMain(GlobalAction.ShowDialog(BackupDialog.AddMoreBackupCards)) - } - } - is BackupAction.ShowEnterAccessCodeScreen -> { - Analytics.send(Onboarding.Backup.SettingAccessCodeStarted()) - } - is BackupAction.CheckAccessCode -> { - Analytics.send(Onboarding.Backup.AccessCodeEntered()) - if (action.accessCode.length < 4) { - store.dispatch(BackupAction.SetAccessCodeError(AccessCodeError.CodeTooShort)) - } else { - store.dispatch(BackupAction.SetAccessCodeError(null)) - store.dispatch(BackupAction.SaveFirstAccessCode(action.accessCode)) - } - } - is BackupAction.SaveAccessCodeConfirmation -> { - Analytics.send(Onboarding.Backup.AccessCodeReEntered()) - if (action.accessCodeConfirmation == backupState.accessCode) { - store.dispatch(BackupAction.SetAccessCodeError(null)) - backupService.setAccessCode(action.accessCodeConfirmation) - store.dispatch(BackupAction.PrepareToWritePrimaryCard) - } else { - store.dispatch(BackupAction.SetAccessCodeError(AccessCodeError.CodesDoNotMatch)) - } - } - is BackupAction.WritePrimaryCard -> { - val isRing = scanResponse?.cardTypesResolver?.isRing() == true - val iconScanRes = if (isRing) R.drawable.img_hand_scan_ring else null - - store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing)) - - tangemSdkManager.changeProductType(isRing) - backupService.proceedBackup(iconScanRes = iconScanRes) { result -> - when (result) { - is CompletionResult.Success -> { - store.dispatchOnMain(BackupAction.PrepareToWriteBackupCard(1)) - } - is CompletionResult.Failure -> Unit - } - tangemSdkManager.clearProductType() - } - } - is BackupAction.WriteBackupCard -> { - val cardIndex = if (action.cardNumber > 0) action.cardNumber - 1 else action.cardNumber - val backupCard = backupState.backupCards.getOrNull(cardIndex) - val isRing = backupCard.isRing() - val iconScanRes = if (isRing) R.drawable.img_hand_scan_ring else null - - store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing)) - - tangemSdkManager.changeProductType(isRing) - backupService.proceedBackup(iconScanRes = iconScanRes) { result -> - when (result) { - is CompletionResult.Success -> { - val backupValidator = BackupValidator() - if (!backupValidator.isValidBackupStatus(CardDTO(result.data))) { - store.dispatchOnMain(BackupAction.ErrorInBackupCard) - } - if (backupService.currentState == BackupService.State.Finished) { - store.dispatchOnMain(BackupAction.FinishBackup()) - } else { - store.dispatchOnMain(BackupAction.PrepareToWriteBackupCard(action.cardNumber + 1)) - } - } - is CompletionResult.Failure -> { - when (val error = result.error) { - is TangemSdkError.BackupFailedNotEmptyWallets -> { - store.dispatchOnMain( - GlobalAction.ShowDialog( - BackupDialog.ResetBackupCard(error.cardId), - ), - ) - } - } - } - } - - tangemSdkManager.clearProductType() - } - } - is BackupAction.DiscardBackup -> { - backupService.discardSavedBackup() - } - is BackupAction.DiscardSavedBackup -> { - mainScope.launch { - backupService.primaryCardId?.let { // always null for onboarding v2 - Analytics.send(Onboarding.Finished()) - store.state.globalState.onboardingState.onboardingManager?.finishActivation(it) - } - backupService.discardSavedBackup() - - val isOnboardingV2Enabled = store.inject(DaggerGraphState::onboardingV2FeatureToggles) - .isOnboardingV2Enabled - - if (isOnboardingV2Enabled) { - val onboardingRepository = store.inject(DaggerGraphState::onboardingRepository) - val cardRepository = store.inject(DaggerGraphState::cardRepository) - val unfinishedBackup = onboardingRepository.getUnfinishedFinalizeOnboarding() ?: return@launch - - cardRepository.finishCardActivation(unfinishedBackup.card.cardId) - onboardingRepository.clearUnfinishedFinalizeOnboarding() - Analytics.send(Onboarding.Finished()) - } - } - } - is BackupAction.CheckForUnfinishedBackup -> { - val isOnboardingV2Enabled = store.inject(DaggerGraphState::onboardingV2FeatureToggles).isOnboardingV2Enabled - - if (isOnboardingV2Enabled) { - val onboardingRepository = store.inject(DaggerGraphState::onboardingRepository) - - mainScope.launch { - val onboardingScanResponse = onboardingRepository.getUnfinishedFinalizeOnboarding() ?: return@launch - store.dispatch(GlobalAction.ShowDialog(BackupDialog.UnfinishedBackupFound(onboardingScanResponse))) - } - } else if (backupService.hasIncompletedBackup) { - store.dispatch(GlobalAction.ShowDialog(BackupDialog.UnfinishedBackupFound())) - } - } - is BackupAction.ResumeFoundUnfinishedBackup -> { - if (action.unfinishedBackupScanResponse != null) { - // onboarding V2 - store.dispatchNavigationAction { - push( - AppRoute.Onboarding( - scanResponse = action.unfinishedBackupScanResponse, - mode = AppRoute.Onboarding.Mode.ContinueFinalize, - ), - ) - } - } else { - store.dispatch( - GlobalAction.Onboarding.StartForUnfinishedBackup( - addedBackupCardsCount = backupService.addedBackupCardsCount, - ), - ) - - store.dispatchNavigationAction { push(AppRoute.OnboardingWallet()) } - } - } - is BackupAction.SkipBackup -> { - Analytics.send(Onboarding.Backup.Skipped()) - Analytics.send(Onboarding.Finished()) - - scope.launch { - launch { - store.state.globalState.onboardingState.onboardingManager?.finishActivation( - cardIds = gatherCardIds(backupState, card), - ) - } - - with(scanResponse) { - if (this == null) { - when (val result = readCard()) { - is CompletionResult.Success -> handleFinishBackup(result.data) - is CompletionResult.Failure -> store.dispatchNavigationAction(AppRouter::pop) - } - } else { - handleFinishBackup(scanResponse = this) - } - } - } - } - is BackupAction.FinishBackup -> { - scope.launch { - if (action.withAnalytics) { - Analytics.send(Onboarding.Backup.Finished(backupState.backupCardsNumber)) - } - - var userWallet: UserWallet? = null - if (scanResponse != null) { - scanResponse = updateScanResponseAfterBackup(scanResponse!!, backupState) - userWallet = createUserWallet( - scanResponse = requireNotNull(value = scanResponse, lazyMessage = { "ScanResponse is null" }), - backupState = backupState, - ) - } else { - delay(HIDE_PROGRESS_DELAY) - - when (val result = readCard()) { - is CompletionResult.Failure -> { - store.dispatchNavigationAction(AppRouter::pop) - return@launch - } - is CompletionResult.Success -> { - scanResponse = result.data - userWallet = createUserWallet(scanResponse = result.data, backupState = backupState) - } - } - } - - val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) - when (backupState.startedSource) { - BackupStartedSource.Onboarding -> saveWallet( - userWalletsListManager = userWalletsListManager, - userWallet = userWallet, - scanResponse = scanResponse, - backupState = backupState, - ) - BackupStartedSource.CreateBackup -> updateWallet( - userWalletsListManager = userWalletsListManager, - userWallet = userWallet, - backupState = backupState, - ) - } - - scope.launch { - if (userWallet.scanResponse.cardTypesResolver.isWallet2() && userWallet.isImported) { - store.inject(DaggerGraphState::walletsRepository).markWallet2WasCreated(userWallet.walletId) - } - } - - val notActivatedCardIds = gatherCardIds(backupState, card).mapNotNull { - if (store.state.globalState.onboardingState.onboardingManager?.isActivationFinished(it) == true) { - null - } else { - it - } - } - - // All cardIds may already be activated if the backup was skipped before. - if (notActivatedCardIds.isEmpty()) { - delay(1000) - store.dispatchWithMain(BackupAction.BackupFinished(userWallet.walletId)) - return@launch - } - - Analytics.send(Onboarding.Finished()) - - store.state.globalState.onboardingState.onboardingManager?.finishActivation(notActivatedCardIds) - handleFinishBackup(requireNotNull(scanResponse), userWallet) - store.dispatchWithMain(BackupAction.BackupFinished(userWalletId = userWallet.walletId)) - } - } - - is BackupAction.ResetBackupCard -> { - scope.launch { tangemSdkManager.resetToFactorySettings(action.cardId, false) } - } - - else -> Unit - } -} - -private fun Card?.isRing(): Boolean { - return this?.let { RING_BATCH_IDS.contains(batchId) || batchId.startsWith(RING_BATCH_PREFIX) } ?: false -} - -private suspend fun saveWallet( - userWalletsListManager: UserWalletsListManager, - userWallet: UserWallet, - scanResponse: ScanResponse?, - backupState: BackupState, -) { - userWalletsListManager.save( - userWallet = userWallet.copy( - scanResponse = updateScanResponseAfterBackup( - scanResponse = requireNotNull( - value = scanResponse, - lazyMessage = { "ScanResponse is null" }, - ), - backupState = backupState, - ), - ), - canOverride = true, - ) -} - -private suspend fun updateWallet( - userWalletsListManager: UserWalletsListManager, - userWallet: UserWallet, - backupState: BackupState, -) { - userWalletsListManager.update( - userWalletId = userWallet.walletId, - update = { wallet -> - wallet.copy( - scanResponse = updateScanResponseAfterBackup( - scanResponse = wallet.scanResponse, - backupState = backupState, - ), - ) - }, - ) -} - -private suspend fun createUserWallet(scanResponse: ScanResponse, backupState: BackupState): UserWallet { - val userWalletBuilder = store.inject(DaggerGraphState::userWalletBuilderFactory).create(scanResponse) - - return requireNotNull( - value = userWalletBuilder - .backupCardsIds(backupState.backupCardIds.toSet()) - .hasBackupError(backupState.hasBackupError) - .build(), - lazyMessage = { "User wallet not created" }, - ) -} - -fun updateArtworks(addedBackupCardsCount: Int, card: Card) { - mainScope.launch { - withIOContext { - val imageUri = loadArtworkForCard(card.cardId, card.cardPublicKey, Uri.EMPTY) - when (addedBackupCardsCount) { - 1 -> { - store.dispatchOnMain(OnboardingWalletAction.SetSecondCardArtworkUrl(imageUri)) - } - 2 -> { - store.dispatchOnMain(OnboardingWalletAction.SetThirdCardArtworkUrl(imageUri)) - } - } - } - } -} - -internal fun gatherCardIds(backupState: BackupState, card: CardDTO?): List { - return (listOf(backupState.primaryCardId, card?.cardId) + backupState.backupCardIds) - .filterNotNull() - .distinct() -} - -private fun handleOnBackPressed(state: OnboardingWalletState) { - when (state.backupState.backupStep) { - null, BackupStep.InitBackup, BackupStep.ScanOriginCard, BackupStep.AddBackupCards, BackupStep.EnterAccessCode, - BackupStep.ReenterAccessCode, BackupStep.SetAccessCode, BackupStep.WritePrimaryCard, - -> { - showInterruptOnboardingDialog() - } - is BackupStep.WriteBackupCard -> { - store.dispatch(GlobalAction.ShowDialog(BackupDialog.BackupInProgress)) - } - BackupStep.Finished -> { - OnboardingHelper.onInterrupted() - store.dispatchNavigationAction(AppRouter::pop) - } - } -} - -private fun showInterruptOnboardingDialog() { - store.dispatchDialogShow( - OnboardingDialog.InterruptOnboarding( - onOk = { - OnboardingHelper.onInterrupted() - store.dispatch(BackupAction.DiscardBackup) - store.dispatchNavigationAction(AppRouter::pop) - }, - ), - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt deleted file mode 100644 index d34a661c97..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt +++ /dev/null @@ -1,185 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.redux - -import com.tangem.domain.redux.OnboardingManageTokensAction -import com.tangem.tap.backupService -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction -import org.rekotlin.Action - -object OnboardingWalletReducer { - fun reduce(action: Action, state: AppState): OnboardingWalletState = internalReduce(action, state) -} - -@Suppress("CyclomaticComplexMethod") -private fun internalReduce(action: Action, appState: AppState): OnboardingWalletState { - val state = appState.onboardingWalletState - val backupState = state.backupState - - return when (action) { - is GlobalAction.Onboarding -> ReducerForGlobalAction.reduce(action, state) - is BackupAction.BackupFinished -> { - state.copy( - step = if (action.userWalletId != null && backupState.startedSource == BackupStartedSource.Onboarding) { - OnboardingWalletStep.ManageTokens - } else { - OnboardingWalletStep.Done - }, - userWalletId = action.userWalletId, - ) - } - is BackupAction -> state.copy(backupState = BackupReducer.reduce(action = action, state = state.backupState)) - is OnboardingWallet2Action -> OnboardingWallet2Reducer.reduce(action, state) - is OnboardingWalletAction.GetToCreateWalletStep -> state.copy( - step = OnboardingWalletStep.CreateWallet, - ) - is OnboardingWalletAction.ResumeBackup -> state.copy(step = OnboardingWalletStep.Backup) - is OnboardingWalletAction.SetPrimaryCardArtworkUrl -> { - state.copy( - walletImages = state.walletImages.copy(primaryCardImage = action.artworkUri), - ) - } - is OnboardingWalletAction.SetSecondCardArtworkUrl -> { - state.copy( - walletImages = state.walletImages.copy(secondCardImage = action.artworkUri), - ) - } - is OnboardingWalletAction.SetThirdCardArtworkUrl -> { - state.copy( - walletImages = state.walletImages.copy(thirdCardImage = action.artworkUri), - ) - } - is OnboardingManageTokensAction.CurrenciesSaved -> state.copy(step = OnboardingWalletStep.Done) - is OnboardingWalletAction.WalletSaved -> state.copy( - step = when (backupState.startedSource) { - BackupStartedSource.Onboarding -> OnboardingWalletStep.ManageTokens - BackupStartedSource.CreateBackup -> OnboardingWalletStep.Done - }, - userWalletId = action.userWalletId, - ) - is OnboardingWalletAction.Done -> state.copy(step = OnboardingWalletStep.Done) - else -> state - } -} - -private object ReducerForGlobalAction { - - private const val MAX_BACKUP_CARDS = 2 - - fun reduce(action: GlobalAction.Onboarding, state: OnboardingWalletState): OnboardingWalletState { - return when (action) { - is GlobalAction.Onboarding.Start -> { - OnboardingWalletState( - backupState = state.backupState.copy( - maxBackupCards = MAX_BACKUP_CARDS, - canSkipBackup = action.canSkipBackup, - startedSource = action.source, - ), - ) - } - is GlobalAction.Onboarding.StartForUnfinishedBackup -> { - OnboardingWalletState( - backupState = state.backupState.copy( - maxBackupCards = action.addedBackupCardsCount, - canSkipBackup = false, - isInterruptedBackup = true, - ), - ) - } - else -> state - } - } -} - -private object OnboardingWallet2Reducer { - fun reduce(action: OnboardingWallet2Action, state: OnboardingWalletState): OnboardingWalletState = when (action) { - is OnboardingWallet2Action.SetDependencies -> state.copy( - wallet2State = OnboardingWallet2State( - maxProgress = action.maxProgress, - ), - ) - else -> state - } -} - -private object BackupReducer { - @Suppress("ComplexMethod", "LongMethod") - fun reduce(action: BackupAction, state: BackupState): BackupState { - return when (action) { - is BackupAction.IntroduceBackup -> BackupState( - backupStep = BackupStep.InitBackup, - maxBackupCards = 2, - canSkipBackup = state.canSkipBackup, - startedSource = state.startedSource, - ) - BackupAction.StartAddingPrimaryCard -> { - state.copy( - backupStep = BackupStep.ScanOriginCard, - maxBackupCards = 2, - canSkipBackup = state.canSkipBackup, - ) - } - BackupAction.StartAddingBackupCards -> { - state.copy( - backupStep = BackupStep.AddBackupCards, - maxBackupCards = 2, - canSkipBackup = state.canSkipBackup, - ) - } - is BackupAction.AddBackupCard.Success -> { - state.copy( - backupCards = state.backupCards + action.card, - backupCardsNumber = state.backupCardsNumber + 1, - ) - } - is BackupAction.AddBackupCard.ChangeButtonLoading -> state.copy(showBtnLoading = action.isLoading) - BackupAction.ShowAccessCodeInfoScreen -> state.copy(backupStep = BackupStep.SetAccessCode) - BackupAction.ShowEnterAccessCodeScreen -> state.copy( - backupStep = BackupStep.EnterAccessCode, - accessCodeError = null, - ) - is BackupAction.SaveFirstAccessCode -> state.copy( - backupStep = BackupStep.ReenterAccessCode, - accessCode = action.accessCode, - ) - is BackupAction.SetAccessCodeError -> state.copy(accessCodeError = action.error) - is BackupAction.PrepareToWritePrimaryCard -> if (state.primaryCardId == null) { - state.copy( - primaryCardId = backupService.primaryCardId, - primaryCardBatchId = backupService.primaryCardBatchId, - backupCardIds = backupService.backupCardIds, - backupCardBatchIds = backupService.backupCardsBatchIds, - backupCardsNumber = backupService.backupCardIds.size, - backupStep = BackupStep.WritePrimaryCard, - ) - } else { - state.copy(backupStep = BackupStep.WritePrimaryCard) - } - is BackupAction.PrepareToWriteBackupCard -> if (state.primaryCardId == null) { - state.copy( - primaryCardId = backupService.primaryCardId, - primaryCardBatchId = backupService.primaryCardBatchId, - backupCardIds = backupService.backupCardIds, - backupCardBatchIds = backupService.backupCardsBatchIds, - backupCardsNumber = backupService.backupCardIds.size, - backupStep = BackupStep.WriteBackupCard(action.cardNumber), - ) - } else { - state.copy(backupStep = BackupStep.WriteBackupCard(action.cardNumber)) - } - is BackupAction.ErrorInBackupCard -> state.copy(hasBackupError = true) - is BackupAction.SkipBackup -> state.copy(backupStep = BackupStep.Finished) - is BackupAction.FinishBackup -> state.copy(backupStep = BackupStep.Finished) - BackupAction.OnAccessCodeDialogClosed -> state.copy(backupStep = BackupStep.AddBackupCards) - BackupAction.DiscardBackup -> BackupState() - is BackupAction.SetHasRing -> { - // Don't update if state.has ring is already true - if (state.hasRing) { - state - } else { - state.copy(hasRing = action.hasRing) - } - } - else -> state - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt deleted file mode 100644 index 8d8f92f601..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt +++ /dev/null @@ -1,128 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.redux - -import android.graphics.Bitmap -import android.net.Uri -import com.tangem.common.card.Card -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.redux.StateDialog -import com.tangem.domain.wallets.models.UserWalletId -import org.rekotlin.StateType - -/** -[REDACTED_AUTHOR] - */ -data class OnboardingWalletState( - val step: OnboardingWalletStep = OnboardingWalletStep.None, - val wallet2State: OnboardingWallet2State? = null, - val backupState: BackupState = BackupState(), - val walletImages: WalletImages = WalletImages(), - val showConfetti: Boolean = false, - val isRingOnboarding: Boolean = false, - val userWalletId: UserWalletId? = null, -) : StateType { - - @Suppress("MagicNumber") - fun getMaxProgress(): Int { - val baseProgress = 7 - return getWallet2Progress() + baseProgress - } - - @Suppress("ComplexMethod", "MagicNumber") - fun getProgressStep(): Int { - val progressByStep = when (step) { - OnboardingWalletStep.CreateWallet, OnboardingWalletStep.None -> 1 - OnboardingWalletStep.Backup -> { - when (backupState.backupStep) { - null -> 2 - BackupStep.InitBackup -> 2 - BackupStep.ScanOriginCard -> 3 - BackupStep.AddBackupCards -> 4 - BackupStep.EnterAccessCode -> 4 - BackupStep.ReenterAccessCode -> 4 - BackupStep.SetAccessCode -> 4 - BackupStep.WritePrimaryCard, is BackupStep.WriteBackupCard -> 5 - BackupStep.Finished -> 6 - } - } - OnboardingWalletStep.ManageTokens -> 6 - OnboardingWalletStep.Done -> getMaxProgress() - } - - return getWallet2Progress() + progressByStep - } - - private fun getWallet2Progress(): Int = wallet2State?.maxProgress ?: 0 -} - -data class WalletImages( - val primaryCardImage: Uri? = null, - val secondCardImage: Uri? = null, - val thirdCardImage: Uri? = null, -) - -data class OnboardingWallet2State( - val maxProgress: Int, -) - -enum class OnboardingWalletStep { - None, CreateWallet, Backup, ManageTokens, Done -} - -data class BackupState( - val primaryCardId: String? = null, - val primaryCardBatchId: String? = null, - val backupCardsNumber: Int = 0, - val backupCards: List = emptyList(), - val backupCardIds: List = emptyList(), - val backupCardBatchIds: List = emptyList(), - @Transient - val backupCardsArtworks: Map = emptyMap(), - val accessCode: String = "", - val accessCodeError: AccessCodeError? = null, - val backupStep: BackupStep? = null, - val maxBackupCards: Int = 2, - val canSkipBackup: Boolean = true, - val isInterruptedBackup: Boolean = false, - val showBtnLoading: Boolean = false, - val hasBackupError: Boolean = false, - val startedSource: BackupStartedSource = BackupStartedSource.Onboarding, - val hasRing: Boolean = false, -) - -enum class BackupStartedSource { - Onboarding, CreateBackup -} - -enum class AccessCodeError { - CodeTooShort, CodesDoNotMatch -} - -typealias CardId = String - -sealed class BackupStep { - data object InitBackup : BackupStep() - data object ScanOriginCard : BackupStep() - data object AddBackupCards : BackupStep() - data object SetAccessCode : BackupStep() - data object EnterAccessCode : BackupStep() - data object ReenterAccessCode : BackupStep() - data object WritePrimaryCard : BackupStep() - data class WriteBackupCard(val cardNumber: Int) : BackupStep() - data object Finished : BackupStep() -} - -sealed class BackupDialog : StateDialog { - data object AttestationFailed : BackupDialog() - data object AddMoreBackupCards : BackupDialog() - data object BackupInProgress : BackupDialog() - - data class UnfinishedBackupFound( - val scanResponse: ScanResponse? = null, - ) : BackupDialog() - - data class ConfirmDiscardingBackup( - val scanResponse: ScanResponse? = null, - ) : BackupDialog() - - data class ResetBackupCard(val cardId: String) : BackupDialog() -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt deleted file mode 100644 index 0927376b54..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt +++ /dev/null @@ -1,314 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui - -import com.google.android.material.button.MaterialButton -import com.tangem.tap.common.extensions.show -import com.tangem.tap.common.postUiDelayBg -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupState -import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.* -import com.tangem.wallet.databinding.FragmentOnboardingWalletBinding - -/** -[REDACTED_AUTHOR] - */ -interface BackupAnimator { - fun updateBackupState(backupState: BackupState) - fun setupCreateWalletState() - fun showBackupIntro(state: BackupState) - fun showScanOriginCard() - fun showAddBackupCards(state: BackupState, backupCardsCounts: Int) - fun showWritePrimaryCard(state: BackupState) - fun showWriteBackupCard(state: BackupState, backupCard: Int) - fun showSuccess(onEnd: () -> Unit) -} - -class WalletBackupAnimator( - private val cardsWidget: WalletCardsWidget, -) : BackupAnimator { - - private val viewState: State = when (cardsWidget.leapfrogWidget.getViewsCount()) { - 2 -> State.TwoCards - 3 -> State.ThreeCards - else -> throw UnsupportedOperationException() - } - - private var currentStep = -1 - private var firstBackupCardAnimated = false - private var secondBackupCardAnimated = false - - override fun updateBackupState(backupState: BackupState) { - } - - override fun showBackupIntro(state: BackupState) { - currentStep = STEP_BACKUP_INTRO - - ORIGIN.show() - FIRST_BACKUP.show() - SECOND_BACKUP.show() - - cardsWidget.toWelcome() - } - - override fun setupCreateWalletState() { - currentStep = STEP_CREATE_WALLET - - cardsWidget.toFolded(false) - - ORIGIN.alpha(1f) - FIRST_BACKUP.alpha(1f) - SECOND_BACKUP.alpha(1f) - } - - override fun showScanOriginCard() { - currentStep = STEP_SCAN_ORIGIN_CARD - - cardsWidget.toFolded() - } - - @Suppress("MagicNumber") - override fun showAddBackupCards(state: BackupState, backupCardsCounts: Int) { - when (backupCardsCounts) { - 0 -> { - when (currentStep) { - UNDEFINED, STEP_CREATE_WALLET -> { - cardsWidget.toFolded(false) { cardsWidget.toFan() } - - FIRST_BACKUP.animateAlpha(0.6f, 0) - SECOND_BACKUP.animateAlpha(0.2f, 400) - } - STEP_BACKUP_INTRO -> { - cardsWidget.toFolded(duration = 300) { cardsWidget.toFan() } - FIRST_BACKUP.animateAlpha(0.6f, 400, 250) - SECOND_BACKUP.animateAlpha(0.2f, 400, 250) - } - STEP_SCAN_ORIGIN_CARD -> { - cardsWidget.toFan() - FIRST_BACKUP.animateAlpha(0.6f, 400, 250) - SECOND_BACKUP.animateAlpha(0.2f, 400, 250) - } - } - } - 1 -> { - cardsWidget.toFan(false) - FIRST_BACKUP.alpha(1f) - SECOND_BACKUP.alpha(0.2f) - } - 2 -> { - cardsWidget.toFan(false) - FIRST_BACKUP.alpha(1f) - SECOND_BACKUP.alpha(1f) - } - } - - currentStep = STEP_ADD_BACKUP_CARDS - } - - @Suppress("MagicNumber") - override fun showWritePrimaryCard(state: BackupState) { - currentStep = STEP_WRITE_PRIMARY_CARD - - cardsWidget.toLeapfrog( - onEndFold = { - FIRST_BACKUP.alpha(0.4f) - SECOND_BACKUP.alpha(0.2f) - }, - ) - } - - @Suppress("MagicNumber") - override fun showWriteBackupCard(state: BackupState, backupCard: Int) { - when (viewState) { - State.TwoCards -> { - if (firstBackupCardAnimated) return - firstBackupCardAnimated = true - - val delay = if (currentStep == UNDEFINED) 700L else 0 - postUiDelayBg(delay) { - FIRST_BACKUP.alpha(1f) - cardsWidget.leapfrogWidget.leap { - ORIGIN.alpha(0.4f) - } - } - } - State.ThreeCards -> { - when (backupCard) { - 1 -> { - if (firstBackupCardAnimated) return - firstBackupCardAnimated = true - - FIRST_BACKUP.alpha(1f) - cardsWidget.leapfrogWidget.leap { - SECOND_BACKUP.alpha(0.4f) - ORIGIN.alpha(0.2f) - } - } - 2 -> { - if (secondBackupCardAnimated) return - secondBackupCardAnimated = true - - /* - * !!! Workaround !!! - * For interrupted backup - * */ - if (!firstBackupCardAnimated) { - showWriteBackupCard(state, backupCard = 1) - return - } - - SECOND_BACKUP.alpha(1f) - cardsWidget.leapfrogWidget.leap { - ORIGIN.alpha(0.4f) - FIRST_BACKUP.alpha(0.2f) - } - } - } - } - } - currentStep = STEP_WRITE_BACKUP_CARD - } - - override fun showSuccess(onEnd: () -> Unit) { - currentStep = STEP_SUCCESS - cardsWidget.leapfrogWidget.fold(onEnd = onEnd) - } - - private enum class State { - ThreeCards, - TwoCards, - } - - private fun BackupCardType.animateAlpha(alpha: Float, duration: Long = 0L, startDelay: Long = 0L) { - when (this) { - ORIGIN -> { - cardsWidget.getOriginCardView().animate().apply { - alpha(alpha) - this.startDelay = startDelay - this.duration = duration - } - } - FIRST_BACKUP -> { - cardsWidget.getFirstBackupCardView().animate().apply { - alpha(alpha) - this.startDelay = startDelay - this.duration = duration - } - } - SECOND_BACKUP -> { - if (viewState != State.ThreeCards) return - cardsWidget.getSecondBackupCardView().animate().apply { - alpha(alpha) - this.startDelay = startDelay - this.duration = duration - } - } - } - } - - private fun BackupCardType.alpha(alpha: Float) { - when (this) { - ORIGIN -> cardsWidget.getOriginCardView().alpha = alpha - FIRST_BACKUP -> cardsWidget.getFirstBackupCardView().alpha = alpha - SECOND_BACKUP -> { - if (viewState != State.ThreeCards) return - cardsWidget.getSecondBackupCardView().alpha = alpha - } - } - } - - private fun BackupCardType.show() { - when (this) { - ORIGIN -> cardsWidget.getOriginCardView().show() - FIRST_BACKUP -> cardsWidget.getFirstBackupCardView().show() - SECOND_BACKUP -> { - if (viewState != State.ThreeCards) return - cardsWidget.getSecondBackupCardView().show() - } - } - } - - companion object { - private const val UNDEFINED = -1 - private const val STEP_CREATE_WALLET = 0 - private const val STEP_BACKUP_INTRO = 1 - private const val STEP_SCAN_ORIGIN_CARD = 2 - private const val STEP_ADD_BACKUP_CARDS = 3 - private const val STEP_WRITE_PRIMARY_CARD = 4 - private const val STEP_WRITE_BACKUP_CARD = 5 - private const val STEP_SUCCESS = 6 - } -} - -class TestBackupAnimation( - private val animator: BackupAnimator, - binding: FragmentOnboardingWalletBinding, -) : BackupAnimator { - - private lateinit var state: BackupState - private var steps = 0 - - init { - init(binding, this) - } - - @Suppress("MagicNumber") - private fun setStep(step: Int, onStepUpdate: (Int) -> Unit = {}) { - steps = step - when (steps) { - 0 -> setupCreateWalletState() - 1 -> showBackupIntro(state) - 2 -> showScanOriginCard() - 3 -> showAddBackupCards(state, 0) - 4 -> showAddBackupCards(state, 1) - 5 -> showAddBackupCards(state, 2) - 6 -> showWritePrimaryCard(state) - 7 -> showWriteBackupCard(state, 1) - 8 -> showWriteBackupCard(state, 2) - else -> setStep(0) - } - onStepUpdate(steps) - } - - fun onNext(onStepUpdate: (Int) -> Unit) { - steps++ - setStep(steps, onStepUpdate) - } - - override fun updateBackupState(backupState: BackupState) { - this.state = backupState - } - - override fun setupCreateWalletState() { - animator.setupCreateWalletState() - } - - override fun showBackupIntro(state: BackupState) { - animator.showBackupIntro(state) - } - - override fun showScanOriginCard() { - animator.showScanOriginCard() - } - - override fun showAddBackupCards(state: BackupState, backupCardsCounts: Int) { - animator.showAddBackupCards(state, backupCardsCounts) - } - - override fun showWritePrimaryCard(state: BackupState) { - animator.showWritePrimaryCard(state) - } - - override fun showWriteBackupCard(state: BackupState, backupCard: Int) { - animator.showWriteBackupCard(state, backupCard) - } - - override fun showSuccess(onEnd: () -> Unit) { - animator.showSuccess(onEnd) - } - - companion object { - fun init(binding: FragmentOnboardingWalletBinding, animator: TestBackupAnimation) { - val button = MaterialButton(binding.onboardingRoot.context).apply { text = "Next" } - button.setOnClickListener { animator.onNext { button.text = "$it" } } - binding.onboardingRoot.addView(button, 0) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt deleted file mode 100644 index 6ea3bf1a25..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.annotation.StringRes -import androidx.recyclerview.widget.RecyclerView -import com.tangem.tap.common.extensions.getString -import com.tangem.wallet.R -import com.tangem.wallet.databinding.ItemBackupInfoAdapterBinding - -class BackupInfoAdapter : RecyclerView.Adapter() { - - private val data = backupInfoSnippets - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackupInfoViewHolder = BackupInfoViewHolder( - ItemBackupInfoAdapterBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false, - ), - ) - - override fun getItemCount(): Int = data.size - - override fun onBindViewHolder(holder: BackupInfoViewHolder, position: Int) = holder.binding.run { - tvHeader.text = root.getString(data[position].header) - tvBody.text = root.getString(data[position].body) - } -} - -private class BackupInfo( - @StringRes val header: Int, - @StringRes val body: Int, -) - -private val backupInfoSnippets = listOf( - BackupInfo( - R.string.onboarding_wallet_info_title_first, - R.string.onboarding_wallet_info_subtitle_first, - ), - BackupInfo( - R.string.onboarding_wallet_info_title_second, - R.string.onboarding_wallet_info_subtitle_second, - ), - BackupInfo( - R.string.onboarding_wallet_info_title_third, - R.string.onboarding_wallet_info_subtitle_third, - ), - BackupInfo( - R.string.onboarding_wallet_info_title_fourth, - R.string.onboarding_wallet_info_subtitle_fourth, - ), - -) - -class BackupInfoViewHolder(val binding: ItemBackupInfoAdapterBinding) : - RecyclerView.ViewHolder(binding.root) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingSeedPhraseStateHandler.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingSeedPhraseStateHandler.kt deleted file mode 100644 index 475a6d64b9..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingSeedPhraseStateHandler.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui - -import android.app.Activity -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.runtime.collectAsState -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.windowsize.rememberWindowSize -import com.tangem.feature.onboarding.api.OnboardingSeedPhraseScreen -import com.tangem.feature.onboarding.api.OnboardingSeedPhraseApi -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseViewModel -import com.tangem.tap.common.extensions.hide -import com.tangem.tap.common.extensions.show -import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState -import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletStep -import com.tangem.wallet.R - -/** -[REDACTED_AUTHOR] - */ -internal class OnboardingSeedPhraseStateHandler( - private val onboardingSeedPhraseApi: OnboardingSeedPhraseApi = OnboardingSeedPhraseScreen(), - private val activity: Activity, -) { - - fun newState( - walletFragment: OnboardingWalletFragment, - state: OnboardingWalletState, - seedPhraseViewModel: SeedPhraseViewModel, - ) { - if (state.step == OnboardingWalletStep.CreateWallet && !seedPhraseViewModel.isFinished) { - switchToWallet2SeedPhraseOnboarding(walletFragment, seedPhraseViewModel, state.getMaxProgress()) - } else { - switchToWalletOnboarding(walletFragment, state) - } - } - - private fun switchToWalletOnboarding(walletFragment: OnboardingWalletFragment, state: OnboardingWalletState) { - walletFragment.bindingSeedPhrase.onboardingSeedPhraseContainer.hide() - walletFragment.pbBinding.pbState.show() - walletFragment.binding.onboardingWalletContainer.show() - walletFragment.handleOnboardingStep(state) - } - - private fun switchToWallet2SeedPhraseOnboarding( - walletFragment: OnboardingWalletFragment, - viewModel: SeedPhraseViewModel, - onboardingWalletMaxProgress: Int, - ) { - walletFragment.pbBinding.pbState.hide() - walletFragment.binding.onboardingWalletContainer.hide() - walletFragment.bindingSeedPhrase.onboardingSeedPhraseContainer.show() - walletFragment.bindingSeedPhrase.onboardingSeedPhraseContainer.setContent { - val subScreen = viewModel.currentScreen.collectAsState().value - setMainScreenToolbarTitle(walletFragment, subScreen) - - TangemTheme( - isDark = isSystemInDarkTheme(), - windowSize = rememberWindowSize(activity = activity), - ) { - onboardingSeedPhraseApi.ScreenContent( - uiState = viewModel.uiState, - subScreen = subScreen, - progress = viewModel.progress.collectAsState(0).value.toFloat() / onboardingWalletMaxProgress, - ) - } - } - } - - private fun setMainScreenToolbarTitle(walletFragment: OnboardingWalletFragment, subScreen: SeedPhraseScreen) { - val titleResId = when (subScreen) { - SeedPhraseScreen.Intro -> R.string.wallet_title - SeedPhraseScreen.AboutSeedPhrase, - SeedPhraseScreen.YourSeedPhrase, - SeedPhraseScreen.CheckSeedPhrase, - -> R.string.onboarding_create_wallet_header - SeedPhraseScreen.ImportSeedPhrase -> R.string.onboarding_seed_intro_button_import - } - - walletFragment.binding.toolbar.title = walletFragment.getString(titleResId) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt deleted file mode 100644 index 99ecf0792a..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ /dev/null @@ -1,691 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui - -import android.content.res.ColorStateList -import android.net.Uri -import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.util.TypedValue -import android.view.View -import android.view.ViewGroup -import android.view.WindowManager -import android.widget.FrameLayout -import android.widget.ImageView -import androidx.appcompat.app.AppCompatActivity -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.ui.Modifier -import androidx.core.view.MenuProvider -import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.transition.TransitionManager -import by.kirich1409.viewbindingdelegate.viewBinding -import coil.load -import com.arkivanov.decompose.defaultComponentContext -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.tabs.TabLayoutMediator -import com.tangem.common.CardIdFormatter -import com.tangem.common.CompletionResult -import com.tangem.common.core.CardIdDisplayFormat -import com.tangem.common.routing.AppRoute -import com.tangem.core.analytics.Analytics -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic -import com.tangem.core.decompose.context.AppComponentContext -import com.tangem.core.decompose.context.childByContext -import com.tangem.core.decompose.di.RootAppComponentContext -import com.tangem.core.ui.UiDependencies -import com.tangem.core.ui.extensions.setStatusBarColor -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.windowsize.rememberWindowSize -import com.tangem.datasource.utils.isNullOrEmpty -import com.tangem.domain.common.util.cardTypesResolver -import com.tangem.domain.feedback.models.FeedbackEmailType -import com.tangem.domain.models.scan.isRing -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.feature.onboarding.data.model.CreateWalletResponse -import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseMediator -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseRouter -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseViewModel -import com.tangem.features.managetokens.component.OnboardingManageTokensComponent -import com.tangem.sdk.ui.widget.leapfrogWidget.LeapfrogWidget -import com.tangem.sdk.ui.widget.leapfrogWidget.PropertyCalculator -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.* -import com.tangem.tap.features.BaseFragment -import com.tangem.tap.features.FragmentOnBackPressedHandler -import com.tangem.tap.features.addBackPressHandler -import com.tangem.tap.features.onboarding.OnboardingMenuProvider -import com.tangem.tap.features.onboarding.products.wallet.redux.* -import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AccessCodeDialog -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.utils.Provider -import com.tangem.wallet.R -import com.tangem.wallet.databinding.FragmentOnboardingWalletBinding -import com.tangem.wallet.databinding.LayoutOnboardingSeedPhraseBinding -import com.tangem.wallet.databinding.ViewOnboardingProgressBinding -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.rekotlin.StoreSubscriber -import timber.log.Timber -import javax.inject.Inject - -@Suppress("LargeClass", "MagicNumber") -@AndroidEntryPoint -class OnboardingWalletFragment : - BaseFragment(R.layout.fragment_onboarding_wallet), - StoreSubscriber, - FragmentOnBackPressedHandler { - - @Inject - internal lateinit var uiDependencies: UiDependencies - - @Inject - internal lateinit var onboardingManageTokensComponentFactory: OnboardingManageTokensComponent.Factory - - @Inject - @RootAppComponentContext - internal lateinit var rootComponentContext: AppComponentContext - - private var onboardingManageTokensComponent: OnboardingManageTokensComponent? = null - private lateinit var onboardingComponentContext: AppComponentContext - - internal val binding: FragmentOnboardingWalletBinding by viewBinding(FragmentOnboardingWalletBinding::bind) - internal val pbBinding: ViewOnboardingProgressBinding by viewBinding(ViewOnboardingProgressBinding::bind) - - internal val bindingSeedPhrase: LayoutOnboardingSeedPhraseBinding by lazy { binding.onboardingSeedPhraseContainer } - private val bindingManageTokens by lazy { binding.onboardingManageTokensContainer } - - private val canSkipBackup by lazy { arguments?.getBoolean(AppRoute.OnboardingWallet.CAN_SKIP_BACKUP_KEY) ?: true } - - private lateinit var seedPhraseStateHandler: OnboardingSeedPhraseStateHandler - - private val seedPhraseViewModel by viewModels() - - private lateinit var cardsWidget: WalletCardsWidget - private var seedPhraseRouter: SeedPhraseRouter? = null - private var accessCodeDialog: AccessCodeDialog? = null - - private lateinit var animator: BackupAnimator - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - seedPhraseStateHandler = OnboardingSeedPhraseStateHandler(activity = requireActivity()) - - val newSeedPhraseRouter = makeSeedPhraseRouter() - seedPhraseRouter = newSeedPhraseRouter - seedPhraseViewModel.setRouter(newSeedPhraseRouter) - seedPhraseViewModel.setMediator(makeSeedPhraseMediator()) - - onboardingComponentContext = rootComponentContext.childByContext( - componentContext = defaultComponentContext(onBackPressedDispatcher = null), - ) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val scaleFactor = getDeviceScaleFactor() - initCardsWidget(createLeapfrogWidget(binding.flCardsContainer, scaleFactor), scaleFactor) - - binding.viewPagerBackupInfo.adapter = BackupInfoAdapter() - TabLayoutMediator( - binding.tabLayoutBackupInfo, - binding.viewPagerBackupInfo, - ) { tab, position -> - // Some implementation - }.attach() - - (activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar) - - addBackPressHandler(handler = this) - - store.dispatch(OnboardingWallet2Action.Init(seedPhraseViewModel.maxProgress)) - store.dispatch(OnboardingWalletAction.Init) - store.dispatch( - OnboardingWalletAction.LoadArtwork( - cardArtworkUriForUnfinishedBackup = requireContext().resourceUri(R.drawable.card_placeholder_wallet), - ), - ) - } - - override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider( - scanResponseProvider = Provider { - store.state.globalState.onboardingState.onboardingManager?.scanResponse - ?: error("ScanResponse must be not null") - }, - ) - - private fun reInitCardsWidgetIfNeeded(backupCardsCounts: Int) = with(binding) { - val viewBackupCount = flCardsContainer.childCount - 1 - if (viewBackupCount <= 0) return@with - if (viewBackupCount == backupCardsCounts) return@with - - cardsWidget.toFolded(false) - - if (viewBackupCount > backupCardsCounts) { - flCardsContainer.removeViews(0, viewBackupCount - backupCardsCounts) - } else { - flCardsContainer.inflate(R.layout.view_onboarding_card, true) - } - - val scaleFactor = getDeviceScaleFactor() - initCardsWidget(createLeapfrogWidget(flCardsContainer, scaleFactor), scaleFactor) - } - - private fun createLeapfrogWidget(container: FrameLayout, deviceScaleFactor: Float): LeapfrogWidget { - val leapfrogCalculator = PropertyCalculator( - yTranslationFactor = when (container.childCount) { - 3 -> 25f - else -> 35f - } * deviceScaleFactor, - ) - return LeapfrogWidget(container, leapfrogCalculator) - } - - private fun initCardsWidget(leapfrogWidget: LeapfrogWidget, deviceScaleFactor: Float, isTest: Boolean = false) { - cardsWidget = WalletCardsWidget(leapfrogWidget, deviceScaleFactor) - animator = if (isTest) { - TestBackupAnimation(WalletBackupAnimator(cardsWidget), binding) - } else { - WalletBackupAnimator(cardsWidget) - } - } - - override fun onStart() { - super.onStart() - store.subscribe(this) { state -> - state.skipRepeats { oldState, newState -> - oldState.onboardingWalletState == newState.onboardingWalletState - }.select { it.onboardingWalletState } - } - setStatusBarColor(R.color.background_primary) - } - - override fun onStop() { - super.onStop() - onboardingManageTokensComponent = null - store.unsubscribe(this) - } - - override fun newState(state: OnboardingWalletState) { - Handler(Looper.getMainLooper()).post { - if (activity == null || view == null) return@post - animator.updateBackupState(state.backupState) - requireActivity().invalidateOptionsMenu() - - pbBinding.pbState.max = state.getMaxProgress() - pbBinding.pbState.progress = state.getProgressStep() - - when { - state.wallet2State != null -> { - seedPhraseStateHandler.newState(this, state, seedPhraseViewModel) - seedPhraseViewModel.setCardArtworkUri( - cardArtworkUri = state.walletImages.primaryCardImage.toString(), - ) - updateWalletImagesState(state.walletImages) - } - else -> { - updateWalletImagesState(state.walletImages) - handleOnboardingStep(state) - } - } - } - } - - private fun updateWalletImagesState(walletImages: WalletImages) { - if (!walletImages.primaryCardImage.isNullOrEmpty()) { - loadImageIntoImageView(walletImages.primaryCardImage, binding.imvFrontCard) - } - if (!walletImages.secondCardImage.isNullOrEmpty()) { - loadImageIntoImageView(walletImages.secondCardImage, binding.imvFirstBackupCard) - } - if (!walletImages.thirdCardImage.isNullOrEmpty()) { - loadImageIntoImageView(walletImages.thirdCardImage, binding.imvSecondBackupCard) - } - } - - private fun loadImageIntoImageView(uri: Uri?, view: ImageView) { - view.load(uri) { - placeholder(R.drawable.card_placeholder_black) - error(R.drawable.card_placeholder_black) - fallback(R.drawable.card_placeholder_black) - } - } - - internal fun handleOnboardingStep(state: OnboardingWalletState) { - when (state.step) { - OnboardingWalletStep.CreateWallet -> setupCreateWalletState() - OnboardingWalletStep.Backup -> setBackupState(state = state.backupState) - OnboardingWalletStep.ManageTokens -> setManageTokensState(requireNotNull(state.userWalletId)) - OnboardingWalletStep.Done -> showSuccess() - else -> {} - } - } - - private fun initializeOnboardingManageTokensComponent(userWalletId: UserWalletId) { - onboardingManageTokensComponent = onboardingManageTokensComponentFactory.create( - context = onboardingComponentContext, - params = OnboardingManageTokensComponent.Params(userWalletId = userWalletId), - onDone = {}, - ) - } - - private fun setManageTokensState(userWalletId: UserWalletId) { - with(binding) { - tvHeader.show() - tvBody.show() - viewPagerBackupInfo.hide() - tabLayoutBackupInfo.hide() - onboardingWalletContainer.show() - layoutButtonsCommon.btnWalletAlternativeAction.hide() - onboardingWalletContainer.hide() - toolbar.title = getText(R.string.onboarding_add_tokens) - } - pbBinding.pbState.show() - bindingSeedPhrase.onboardingSeedPhraseContainer.hide() - if (onboardingManageTokensComponent == null) { - initializeOnboardingManageTokensComponent(userWalletId) - } - with(bindingManageTokens) { - onboardingManageTokensContainer.hide() - onboardingManageTokensContainer.show() - onboardingManageTokensContainer.setContent { - TangemTheme( - isDark = isSystemInDarkTheme(), - windowSize = rememberWindowSize(activity = requireActivity()), - ) { - onboardingManageTokensComponent?.Content(modifier = Modifier.fillMaxSize()) - } - } - } - } - - private fun setupCreateWalletState() = with(binding) { - layoutButtonsCommon.btnWalletMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) - layoutButtonsCommon.btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) - - layoutButtonsCommon.btnWalletMainAction.setOnClickListener { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) - store.dispatch(OnboardingWalletAction.CreateWallet) - } - layoutButtonsCommon.btnWalletAlternativeAction.hide() - - toolbar.title = getText(R.string.onboarding_getting_started) - - tvHeader.setText(R.string.onboarding_create_wallet_header) - tvBody.setText(R.string.onboarding_create_wallet_body) - - animator.setupCreateWalletState() - } - - private fun setBackupState(state: BackupState) { - when (state.backupStep) { - null -> Unit - BackupStep.InitBackup -> showBackupIntro(state) - BackupStep.ScanOriginCard -> showScanOriginCard() - BackupStep.AddBackupCards -> showAddBackupCards(state) - BackupStep.SetAccessCode -> showSetAccessCode() - BackupStep.EnterAccessCode -> showEnterAccessCode(state) - BackupStep.ReenterAccessCode -> showReenterAccessCode(state) - is BackupStep.WritePrimaryCard -> showWritePrimaryCard(state) - is BackupStep.WriteBackupCard -> showWriteBackupCard(state) - BackupStep.Finished -> { - // don't need to navigate here" - // showSuccess() - } - } - } - - private fun showBackupIntro(state: BackupState) = with(binding) { - imvFirstBackupCard.show() - imvSecondBackupCard.show() - - tvHeader.hide() - tvBody.hide() - viewPagerBackupInfo.show() - tabLayoutBackupInfo.show() - - with(layoutButtonsCommon) { - btnWalletMainAction.text = getText(R.string.onboarding_button_backup_now) - btnWalletMainAction.icon = null - btnWalletMainAction.setOnClickListener { store.dispatch(BackupAction.StartBackup) } - - btnWalletAlternativeAction.text = getText(R.string.onboarding_button_skip_backup) - btnWalletAlternativeAction.setOnClickListener { store.dispatch(BackupAction.SkipBackup) } - btnWalletAlternativeAction.show(state.canSkipBackup && canSkipBackup) - } - animator.showBackupIntro(state) - } - - private fun showScanOriginCard() = with(binding) { - prepareBackupView() - tvHeader.text = getText(R.string.onboarding_title_scan_origin_card) - tvBody.text = getString( - R.string.onboarding_subtitle_scan_primary, - ) - - with(layoutButtonsCommon) { - btnWalletMainAction.text = getString(R.string.onboarding_button_scan_origin_card) - btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) - btnWalletAlternativeAction.hide() - btnWalletMainAction.setOnClickListener { store.dispatch(BackupAction.ScanPrimaryCard) } - } - - animator.showScanOriginCard() - } - - private fun showAddBackupCards(state: BackupState) = with(binding) { - prepareBackupView() - - accessCodeDialog?.dismiss() - accessCodeDialog = null - - layoutButtonsAddCards.root.show() - layoutButtonsCommon.root.hide() - layoutButtonsAddCards.btnAddCard.setIconResource(R.drawable.ic_tangem_24) - if (state.showBtnLoading) { - layoutButtonsAddCards.btnAddCard.iconTint = ColorStateList.valueOf( - resources.getColor(R.color.button_secondary), - ) - layoutButtonsAddCards.btnAddCard.text = "" - layoutButtonsAddCards.btnAddCard.isEnabled = false - layoutButtonsAddCards.btnProgress.show() - } else { - layoutButtonsAddCards.btnAddCard.iconTint = ColorStateList.valueOf( - resources.getColor(R.color.icon_primary_1), - ) - layoutButtonsAddCards.btnProgress.hide() - layoutButtonsAddCards.btnAddCard.text = getText(R.string.onboarding_button_add_backup_card) - layoutButtonsAddCards.btnAddCard.isEnabled = true - } - if (state.backupCardsNumber < state.maxBackupCards) { - layoutButtonsAddCards.btnAddCard.setOnClickListener { - store.dispatch(BackupAction.AddBackupCard) - } - } else { - layoutButtonsAddCards.btnAddCard.isEnabled = false - } - - layoutButtonsAddCards.btnContinue.text = getText(R.string.onboarding_button_finalize_backup) - layoutButtonsAddCards.btnContinue.setOnClickListener { store.dispatch(BackupAction.FinishAddingBackupCards) } - layoutButtonsAddCards.btnContinue.isEnabled = state.backupCardsNumber != 0 - when (state.backupCardsNumber) { - 0 -> { - tvHeader.text = getText(R.string.onboarding_title_no_backup_cards) - tvBody.text = getText(R.string.onboarding_subtitle_no_backup_cards) - } - 1 -> { - tvHeader.text = getText(R.string.onboarding_title_one_backup_card) - tvBody.text = getText(R.string.onboarding_subtitle_one_backup_card) - } - 2 -> { - tvHeader.text = getText(R.string.onboarding_title_two_backup_cards) - tvBody.text = getText(R.string.onboarding_subtitle_two_backup_cards) - } - else -> {} - } - - animator.showAddBackupCards(state, state.backupCardsNumber) - } - - private fun prepareBackupView() = with(binding) { - toolbar.title = getText(R.string.onboarding_navbar_title_creating_backup) - - tvHeader.show() - tvBody.show() - viewPagerBackupInfo.hide() - tabLayoutBackupInfo.hide() - - imvFirstBackupCard.show() - imvSecondBackupCard.show() - } - - private fun showSetAccessCode() { - accessCodeDialog = AccessCodeDialog(requireContext()).apply { - dismissWithAnimation = true - create() - setOnCancelListener { - store.dispatch(BackupAction.OnAccessCodeDialogClosed) - } - - setOnShowListener { setSecurityMode(true) } - - setOnDismissListener { setSecurityMode(false) } - - show() - showInfoScreen() - val view = - delegate.findViewById(com.google.android.material.R.id.design_bottom_sheet) - (view?.parent as? ViewGroup)?.let { TransitionManager.beginDelayedTransition(it) } - behavior.state = BottomSheetBehavior.STATE_EXPANDED - window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) - view?.let { it.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT } - } - } - - private fun showEnterAccessCode(state: BackupState) { - accessCodeDialog?.showEnterAccessCode() - accessCodeDialog?.showError(state.accessCodeError) - } - - private fun showReenterAccessCode(state: BackupState) { - accessCodeDialog?.showReenterAccessCode() - accessCodeDialog?.showError(state.accessCodeError) - } - - private fun showWritePrimaryCard(state: BackupState) = with(binding) { - accessCodeDialog?.dismiss() - - reInitCardsWidgetIfNeeded(state.backupCardsNumber) - prepareViewForFinalizeStep() - - val isRing = state.primaryCardBatchId != null && isRing(batchId = state.primaryCardBatchId) - - tvHeader.text = getText( - if (isRing) R.string.common_origin_ring else R.string.common_origin_card, - ) - - tvBody.text = if (isRing) { - getString(R.string.onboarding_subtitle_scan_ring) - } else { - val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4)) - getString( - R.string.onboarding_subtitle_scan_primary_card_format, - state.primaryCardId?.let { cardIdFormatter.getFormattedCardId(it) }, - ) - } - - layoutButtonsCommon.btnWalletMainAction.text = getText( - if (isRing) R.string.onboarding_button_backup_ring else R.string.onboarding_button_backup_origin, - ) - - layoutButtonsCommon.btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) - layoutButtonsCommon.btnWalletMainAction.setOnClickListener { store.dispatch(BackupAction.WritePrimaryCard) } - - animator.showWritePrimaryCard(state) - } - - private fun prepareViewForFinalizeStep() = with(binding) { - toolbar.title = getText(R.string.onboarding_button_finalize_backup) - - layoutButtonsAddCards.root.hide() - layoutButtonsCommon.root.show() - layoutButtonsCommon.btnWalletAlternativeAction.hide() - - imvCardBackground.hide() - imvFirstBackupCard.show() - imvSecondBackupCard.show() - } - - private fun showWriteBackupCard(state: BackupState) = with(binding) { - reInitCardsWidgetIfNeeded(state.backupCardsNumber) - prepareViewForFinalizeStep() - - val cardNumber = (state.backupStep as? BackupStep.WriteBackupCard)?.cardNumber ?: 1 - - val isRing = isRing(batchId = state.backupCardBatchIds[cardNumber - 1]) - tvHeader.text = getString( - if (isRing) R.string.onboarding_title_backup_ring else R.string.onboarding_title_backup_card, - ) - - tvBody.text = if (isRing) { - getString(R.string.onboarding_subtitle_scan_ring) - } else { - val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4)) - getString( - R.string.onboarding_subtitle_scan_backup_card_format, - cardIdFormatter.getFormattedCardId(state.backupCardIds[cardNumber - 1]), - ) - } - - layoutButtonsCommon.btnWalletMainAction.text = getString( - if (isRing) R.string.onboarding_button_backup_ring else R.string.onboarding_button_backup_origin, - ) - - layoutButtonsCommon.btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) - layoutButtonsCommon.btnWalletMainAction.setOnClickListener { - store.dispatch(BackupAction.WriteBackupCard(cardNumber)) - } - - animator.showWriteBackupCard(state, cardNumber) - } - - private fun showSuccess() = with(binding) { - toolbar.title = getString(R.string.onboarding_done_header) - tvHeader.text = getText(R.string.onboarding_done_header) - - tvHeader.show() - tvBody.show() - viewPagerBackupInfo.hide() - tabLayoutBackupInfo.hide() - onboardingWalletContainer.show() - bindingManageTokens.onboardingManageTokensContainer.hide() - - tvBody.text = getText(R.string.onboarding_subtitle_success_tangem_wallet_onboarding) - layoutButtonsCommon.btnWalletMainAction.text = getText(R.string.onboarding_button_continue_wallet) - layoutButtonsCommon.btnWalletMainAction.icon = null - layoutButtonsCommon.btnWalletAlternativeAction.hide() - layoutButtonsCommon.btnWalletMainAction.setOnClickListener { - showConfetti(false) - store.dispatch(OnboardingWalletAction.FinishOnboarding(scope = requireActivity().lifecycleScope)) - } - - animator.showSuccess { - if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { - flCardsContainer.hide() - imvCardBackground.hide() - showConfetti(true) - imvSuccess.alpha = 0f - imvSuccess.show() - imvSuccess.animate()?.alpha(1f)?.duration = 400 - } - } - } - - internal fun showConfetti(show: Boolean) { - if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { - with(binding.vConfetti) { - lavConfetti.show(show) - - if (show) { - lavConfetti.playAnimation() - } else { - lavConfetti.cancelAnimation() - } - } - } - } - - override fun handleOnBackPressed() { - // workaround to use right navigation back for toolbar back btn on seed phrase flow - val isWallet2 = - store.state.globalState.onboardingState.onboardingManager?.scanResponse?.cardTypesResolver?.isWallet2() - ?: false - val seedPhraseRouter = seedPhraseRouter - if (seedPhraseRouter != null && isWallet2) { - seedPhraseRouter.navigateBack() - } else { - legacyOnBackHandler() - } - } - - private fun legacyOnBackHandler() { - store.dispatch(OnboardingWalletAction.OnBackPressed) - } - - private fun getDeviceScaleFactor(): Float { - val typedValue = TypedValue() - resources.getValue(R.dimen.device_scale_factor_for_twins_welcome, typedValue, true) - return typedValue.float - } - - private fun makeSeedPhraseRouter(): SeedPhraseRouter = SeedPhraseRouter( - onBack = ::legacyOnBackHandler, - onOpenChat = { - Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro)) - - val scanResponse = requireNotNull(store.state.globalState.onboardingState.onboardingManager?.scanResponse) - - val getCardInfoUseCase = store.inject(DaggerGraphState::getCardInfoUseCase) - val cardInfo = requireNotNull(getCardInfoUseCase.invoke(scanResponse).getOrNull()) - - scope.launch { - store.inject(DaggerGraphState::sendFeedbackEmailUseCase) - .invoke(type = FeedbackEmailType.DirectUserRequest(cardInfo)) - } - }, - onOpenUriClick = { uri -> - store.dispatchOpenUrl(uri.toString()) - }, - ) - - private fun makeSeedPhraseMediator(): SeedPhraseMediator { - return object : SeedPhraseMediator { - override fun createWallet(callback: (CompletionResult) -> Unit) { - store.dispatch(OnboardingWallet2Action.CreateWallet(callback)) - } - - override fun onWalletCreated(result: CompletionResult) { - store.dispatch(OnboardingWallet2Action.WalletWasCreated(result)) - } - - override fun importWallet( - mnemonicComponents: List, - passphrase: String?, - seedPhraseSource: SeedPhraseSource, - callback: (CompletionResult) -> Unit, - ) { - store.dispatch( - OnboardingWallet2Action.ImportWallet( - mnemonicComponents, - passphrase, - seedPhraseSource, - callback, - ), - ) - } - - override fun allowScreenshots(allow: Boolean) { - setSecurityMode(value = !allow) - } - } - } - - private fun setSecurityMode(value: Boolean) { - Timber.d("Security mode: ${if (value) "enabled" else "disabled"}") - - if (value) { - requireActivity().window.setFlags( - WindowManager.LayoutParams.FLAG_SECURE, - WindowManager.LayoutParams.FLAG_SECURE, - ) - } else { - requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt deleted file mode 100644 index 4a06365222..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt +++ /dev/null @@ -1,240 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui - -import android.animation.AnimatorSet -import android.animation.ObjectAnimator -import android.animation.PropertyValuesHolder -import android.view.View -import android.widget.ImageView -import androidx.core.animation.doOnEnd -import com.tangem.sdk.ui.widget.leapfrogWidget.LeapView -import com.tangem.sdk.ui.widget.leapfrogWidget.LeapfrogWidget - -class WalletCardsWidget( - val leapfrogWidget: LeapfrogWidget, - private val deviceScaleFactor: Float = 1f, -) { - - private val animDuration: Long = 400 - - private var currentState: WidgetState? = null - - fun toWelcome(animate: Boolean = true, onEnd: () -> Unit = {}) { - if (currentState == WidgetState.WELCOME) return - - currentState = WidgetState.WELCOME - - val animator = createAnimator(animate, onEnd = onEnd) - animator.playTogether(createAnimators(::createWelcomeProperties)) - leapfrogWidget.fold { animator.start() } - } - - fun toFolded(animate: Boolean = true, duration: Long = animDuration, onEnd: () -> Unit = {}) { - if (currentState == WidgetState.FOLDED) return - - currentState = WidgetState.FOLDED - - val animator = createAnimator(animate, duration) { - leapfrogWidget.fold(animate, onEnd) - } - animator.playTogether(createAnimators(::createLeapfrogProperties)) - animator.start() - } - - fun toFan(animate: Boolean = true, onEnd: () -> Unit = {}) { - if (currentState == WidgetState.FAN) return - - currentState = WidgetState.FAN - - val animator = createAnimator(animate, onEnd = onEnd) - animator.playTogether(createAnimators(::createFanProperties)) - leapfrogWidget.fold { animator.start() } - } - - fun toLeapfrog(animate: Boolean = true, onEndFold: () -> Unit = {}, onEnd: () -> Unit = {}) { - if (currentState == WidgetState.LEAPFROG) return - - currentState = WidgetState.LEAPFROG - - val onAnimatorEnd = { - leapfrogWidget.fold(animate) { - leapfrogWidget.initViews() - onEndFold() - leapfrogWidget.unfold(animate, onEnd) - } - } - val animator = createAnimator(animate, onEnd = onAnimatorEnd) - animator.playTogether(createAnimators(::createLeapfrogProperties)) - animator.start() - } - - private fun createAnimators(propertyFactory: (BackupCardType) -> CardProperties): List { - return getCardTypesTypes().map { createCardAnimator(it, propertyFactory(it)) } - } - - @Suppress("MagicNumber") - private fun getCardTypesTypes(): List = when (leapfrogWidget.getViewsCount()) { - 2 -> listOf(BackupCardType.ORIGIN, BackupCardType.FIRST_BACKUP) - 3 -> listOf(BackupCardType.ORIGIN, BackupCardType.FIRST_BACKUP, BackupCardType.SECOND_BACKUP) - else -> throw UnsupportedOperationException() - } - - private fun createAnimator(animate: Boolean, duration: Long = animDuration, onEnd: () -> Unit): AnimatorSet { - return AnimatorSet().apply { - this.duration = if (animate) duration else 0 - doOnEnd { onEnd() } - } - } - - private fun createCardAnimator(cardType: BackupCardType, properties: CardProperties): ObjectAnimator { - val view = getLeapViewByCard(cardType).view - val animator = ObjectAnimator.ofPropertyValuesHolder( - view, - *properties.createValuesHolders().toTypedArray(), - ) - view.elevation = properties.elevation - return animator - } - - @Suppress("MagicNumber") - private fun createWelcomeProperties(cardType: BackupCardType): CardProperties { - return when (cardType) { - BackupCardType.ORIGIN -> CardProperties( - xTranslation = 440f * deviceScaleFactor, - yTranslation = 70f, - rotation = 75f, - elevation = 2f, - scale = .85f * deviceScaleFactor, - ) - BackupCardType.FIRST_BACKUP -> CardProperties( - xTranslation = 10f * deviceScaleFactor, - yTranslation = -30f, - rotation = 100f, - elevation = 1f, - scale = .85f * deviceScaleFactor, - ) - BackupCardType.SECOND_BACKUP -> CardProperties( - xTranslation = -440f * deviceScaleFactor, - yTranslation = -30f, - rotation = 70f, - elevation = 0f, - scale = .85f * deviceScaleFactor, - ) - } - } - - @Suppress("MagicNumber") - private fun createFanProperties(cardType: BackupCardType): CardProperties { - return when (cardType) { - BackupCardType.ORIGIN -> CardProperties( - xTranslation = 0f, - yTranslation = 30f, - rotation = 5f, - elevation = 2f, - scale = 1f * deviceScaleFactor, - ) - BackupCardType.FIRST_BACKUP -> CardProperties( - xTranslation = 0f, - yTranslation = -50f, - rotation = -5f, - elevation = 1f, - scale = 0.9f * deviceScaleFactor, - ) - BackupCardType.SECOND_BACKUP -> CardProperties( - xTranslation = 10f, - yTranslation = -120f, - rotation = -20f, - elevation = 0f, - scale = 0.8f * deviceScaleFactor, - ) - } - } - - @Suppress("MagicNumber") - private fun createLeapfrogProperties(cardType: BackupCardType): CardProperties { - return when (cardType) { - BackupCardType.ORIGIN -> CardProperties( - xTranslation = 0f, - yTranslation = 0f, - rotation = 0f, - elevation = 2f, - scale = 1f * deviceScaleFactor, - ) - BackupCardType.FIRST_BACKUP -> CardProperties( - xTranslation = 0f, - yTranslation = 0f, - rotation = 0f, - elevation = 1f, - scale = 0.9f * deviceScaleFactor, - ) - BackupCardType.SECOND_BACKUP -> CardProperties( - xTranslation = 0f, - yTranslation = 0f, - rotation = 0f, - elevation = 0f, - scale = 0.8f * deviceScaleFactor, - ) - } - } - - @Throws(UnsupportedOperationException::class) - fun getOriginCardView(): ImageView { - return getLeapViewByCard(BackupCardType.ORIGIN).view as ImageView - } - - @Throws(UnsupportedOperationException::class) - fun getFirstBackupCardView(): ImageView { - return getLeapViewByCard(BackupCardType.FIRST_BACKUP).view as ImageView - } - - @Throws(UnsupportedOperationException::class) - fun getSecondBackupCardView(): ImageView { - return getLeapViewByCard(BackupCardType.SECOND_BACKUP).view as ImageView - } - - @Suppress("MagicNumber") - @Throws(UnsupportedOperationException::class) - private fun getLeapViewByCard(cardType: BackupCardType): LeapView { - fun getByIndex(index: Int): LeapView { - return leapfrogWidget.getViewByPosition(leapfrogWidget.getViewPositionByIndex(index)) - } - - return when (leapfrogWidget.getViewsCount()) { - 2 -> when (cardType) { - BackupCardType.ORIGIN -> getByIndex(1) - BackupCardType.FIRST_BACKUP -> getByIndex(0) - BackupCardType.SECOND_BACKUP -> throw UnsupportedOperationException() - } - 3 -> when (cardType) { - BackupCardType.ORIGIN -> getByIndex(2) - BackupCardType.FIRST_BACKUP -> getByIndex(1) - BackupCardType.SECOND_BACKUP -> getByIndex(0) - } - else -> throw UnsupportedOperationException() - } - } - - enum class WidgetState { WELCOME, FOLDED, FAN, LEAPFROG } -} - -enum class BackupCardType { ORIGIN, FIRST_BACKUP, SECOND_BACKUP } - -private data class CardProperties( - val xTranslation: Float = 0f, - val yTranslation: Float = 0f, - val rotation: Float = 0f, - val elevation: Float = 0f, - val scale: Float = 1.1f, -) { - - fun createValuesHolders(): List { - return listOf( - PropertyValuesHolder.ofFloat(View.TRANSLATION_X, xTranslation), - PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, yTranslation), - PropertyValuesHolder.ofFloat(View.ROTATION, rotation), - PropertyValuesHolder.ofFloat(View.SCALE_X, scale), - PropertyValuesHolder.ofFloat(View.SCALE_Y, scale), - ) - } - - companion object -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AccessCodeDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AccessCodeDialog.kt deleted file mode 100644 index bdeec1a22b..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AccessCodeDialog.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs - -import android.content.Context -import android.content.DialogInterface -import android.os.Bundle -import android.view.LayoutInflater -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.bottomsheet.BottomSheetDialog -import com.tangem.tap.common.extensions.hide -import com.tangem.tap.common.extensions.show -import com.tangem.tap.features.onboarding.products.wallet.redux.AccessCodeError -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction -import com.tangem.tap.store -import com.tangem.wallet.R -import com.tangem.wallet.databinding.LayoutBackupAccessCodeBinding - -class AccessCodeDialog(context: Context) : BottomSheetDialog(context) { - - private var binding: LayoutBackupAccessCodeBinding? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = LayoutBackupAccessCodeBinding - .inflate(LayoutInflater.from(context)) - setContentView(binding!!.root) - behavior.state = BottomSheetBehavior.STATE_EXPANDED - } - - override fun setOnDismissListener(listener: DialogInterface.OnDismissListener?) { - super.setOnDismissListener { - listener?.onDismiss(it) - binding = null - } - } - - fun showInfoScreen() = binding?.run { - behavior.state = BottomSheetBehavior.STATE_EXPANDED - accessCodeTitle.text = context.getText(R.string.onboarding_access_code_intro_title) - layoutBackupAccessCodeInfo.root.show() - layoutBackupAccessCodeSubmit.root.hide() - layoutBackupAccessCodeInfo.btnAccessCodeCreate.setOnClickListener { - store.dispatch(BackupAction.ShowEnterAccessCodeScreen) - } - } - - fun showEnterAccessCode() = binding?.run { - layoutBackupAccessCodeInfo.root.hide() - layoutBackupAccessCodeSubmit.root.show() - accessCodeTitle.text = context.getText(R.string.onboarding_access_code_intro_title) - - with(layoutBackupAccessCodeSubmit) { - btnAccessCodeSubmit.text = context.getText(R.string.common_continue) - btnAccessCodeSubmit.setOnClickListener { - store.dispatch(BackupAction.CheckAccessCode(etAccessCode.text.toString())) - } - } - } - - fun showReenterAccessCode() = binding?.run { - layoutBackupAccessCodeInfo.root.hide() - layoutBackupAccessCodeSubmit.root.show() - accessCodeTitle.text = context.getText(R.string.onboarding_access_code_repeat_code_title) - with(layoutBackupAccessCodeSubmit) { - etAccessCode.setText("") - btnAccessCodeSubmit.text = context.getText(R.string.common_submit) - btnAccessCodeSubmit.setOnClickListener { - store.dispatch(BackupAction.SaveAccessCodeConfirmation(etAccessCode.text.toString())) - } - } - } - - fun showError(error: AccessCodeError?) = binding?.layoutBackupAccessCodeSubmit?.run { - when (error) { - AccessCodeError.CodeTooShort -> - tilAccessCode.error = context.getString(R.string.onboarding_access_code_too_short) - AccessCodeError.CodesDoNotMatch -> - tilAccessCode.error = context.getString(R.string.onboarding_access_codes_doesnt_match) - null -> tilAccessCode.error = null - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AddMoreBackupCardsDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AddMoreBackupCardsDialog.kt deleted file mode 100644 index 07a64cc81e..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AddMoreBackupCardsDialog.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs - -import android.content.Context -import androidx.appcompat.app.AlertDialog -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction -import com.tangem.tap.store -import com.tangem.wallet.R - -object AddMoreBackupCardsDialog { - fun create(context: Context): AlertDialog { - return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply { - setTitle(R.string.common_warning) - setMessage(R.string.onboarding_alert_message_not_max_backup_cards_added) - setPositiveButton(R.string.common_continue) { _, _ -> - store.dispatch(BackupAction.ShowAccessCodeInfoScreen) - } - setNegativeButton(R.string.common_cancel) { _, _ -> - } - setOnDismissListener { - store.dispatch(GlobalAction.HideDialog) - } - }.create() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AttestationFailedDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AttestationFailedDialog.kt deleted file mode 100644 index 5b6c8b8c85..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/AttestationFailedDialog.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs - -import android.content.Context -import androidx.appcompat.app.AlertDialog -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.store -import com.tangem.wallet.R - -internal object AttestationFailedDialog { - - fun create(context: Context): AlertDialog { - return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply { - setTitle(R.string.common_error) - setMessage(R.string.issuer_signature_loading_failed) - setPositiveButton(R.string.common_ok) { dialog, _ -> - dialog.dismiss() - } - setOnDismissListener { - store.dispatch(GlobalAction.HideDialog) - } - }.create() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/BackupInProgressDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/BackupInProgressDialog.kt deleted file mode 100644 index 5094c1f4e9..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/BackupInProgressDialog.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs - -import android.content.Context -import androidx.appcompat.app.AlertDialog -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.store -import com.tangem.wallet.R - -object BackupInProgressDialog { - fun create(context: Context): AlertDialog { - return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply { - setTitle(R.string.common_warning) - setMessage(R.string.onboarding_backup_exit_warning) - setPositiveButton(R.string.warning_button_ok) { _, _ -> - store.dispatch(GlobalAction.HideDialog) - } - setOnDismissListener { - store.dispatch(GlobalAction.HideDialog) - } - }.create() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/InterruptOnboardingDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/InterruptOnboardingDialog.kt deleted file mode 100644 index f0249cfcd2..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/InterruptOnboardingDialog.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs - -import android.app.Dialog -import android.content.Context -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.tangem.tap.common.extensions.dispatchDialogHide -import com.tangem.tap.features.onboarding.OnboardingDialog -import com.tangem.tap.store -import com.tangem.wallet.R - -/** -[REDACTED_AUTHOR] - */ -object InterruptOnboardingDialog { - fun create(context: Context, dialog: OnboardingDialog.InterruptOnboarding): Dialog { - return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply { - setTitle(context.getString(R.string.onboarding_exit_alert_title)) - setMessage(context.getString(R.string.onboarding_exit_alert_message)) - setPositiveButton(R.string.common_ok) { _, _ -> dialog.onOk() } - setNegativeButton(R.string.common_cancel) { _, _ -> } - setOnDismissListener { store.dispatchDialogHide() } - setCancelable(false) - }.create() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/ResetBackupCardDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/ResetBackupCardDialog.kt deleted file mode 100644 index 90458e6f63..0000000000 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/ResetBackupCardDialog.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs - -import android.content.Context -import androidx.appcompat.app.AlertDialog -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction -import com.tangem.tap.store -import com.tangem.wallet.R - -object ResetBackupCardDialog { - fun create(context: Context, cardId: String): AlertDialog { - return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply { - setTitle(R.string.common_attention) - setMessage(R.string.onboarding_linking_error_card_with_wallets) - setPositiveButton(R.string.common_cancel) { _, _ -> - Analytics.send(Onboarding.Backup.ResetCancelEvent) - } - setNegativeButton(R.string.card_settings_action_sheet_reset) { _, _ -> - Analytics.send(Onboarding.Backup.ResetPerformEvent) - store.dispatch(BackupAction.ResetBackupCard(cardId)) - } - setOnDismissListener { - store.dispatch(GlobalAction.HideDialog) - } - }.create() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index c829c5ad78..d7a44e57fd 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -33,10 +33,6 @@ import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent import com.tangem.tap.features.details.ui.securitymode.api.SecurityModeComponent import com.tangem.tap.features.details.ui.walletconnect.api.WalletConnectComponent import com.tangem.tap.features.home.api.HomeComponent -import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment -import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment -import com.tangem.tap.features.onboarding.products.twins.ui.OnboardingTwinsFragment -import com.tangem.tap.features.onboarding.products.wallet.ui.OnboardingWalletFragment import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment import com.tangem.tap.features.welcome.component.WelcomeComponent import com.tangem.tap.routing.component.RoutingComponent.Child @@ -423,11 +419,7 @@ internal class ChildFactory @Inject constructor( componentFactory = nftSendComponentFactory, ) } - is AppRoute.OnboardingNote, is AppRoute.SaveWallet, - is AppRoute.OnboardingOther, - is AppRoute.OnboardingTwins, - is AppRoute.OnboardingWallet, -> error("Unsupported route: $route") } // endregion @@ -545,18 +537,6 @@ internal class ChildFactory @Inject constructor( componentFactory = manageTokensComponentFactory, ) } - is AppRoute.OnboardingNote -> { - route.asFragmentChild(Provider { OnboardingNoteFragment() }) - } - is AppRoute.OnboardingOther -> { - route.asFragmentChild(Provider { OnboardingOtherCardsFragment() }) - } - is AppRoute.OnboardingTwins -> { - route.asFragmentChild(Provider { OnboardingTwinsFragment() }) - } - is AppRoute.OnboardingWallet -> { - route.asFragmentChild(Provider { OnboardingWalletFragment() }) - } is AppRoute.QrScanning -> { val source = when (route.source) { is AppRoute.QrScanning.Source.Send -> SourceType.SEND diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index ca72fdcd9a..24ed3c80f7 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -40,27 +40,6 @@ sealed class AppRoute(val path: String) : Route { val isTosAccepted: Boolean, ) : AppRoute(path = "/disclaimer${if (isTosAccepted) "/tos_accepted" else ""}") - @Serializable - data object OnboardingNote : AppRoute(path = "/onboarding/note") - - @Serializable - data class OnboardingWallet( - val canSkipBackup: Boolean = true, - ) : AppRoute(path = "/onboarding/wallet${if (canSkipBackup) "/skippable" else ""}"), RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val CAN_SKIP_BACKUP_KEY = "canSkipBackup" - } - } - - @Serializable - data object OnboardingTwins : AppRoute(path = "/onboarding/twins") - - @Serializable - data object OnboardingOther : AppRoute(path = "/onboarding/other") - @Serializable data object Wallet : AppRoute(path = "/wallet") diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index eb8297c289..57f18c60fc 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -7,10 +7,6 @@ "name": "ONRAMP_ENABLED", "version": "undefined" }, - { - "name": "ONBOARDING_CODE_REFACTORING_ENABLED", - "version": "5.22.0" - }, { "name": "NAVIGATION_REFACTORING", "version": "5.23.0" @@ -47,10 +43,6 @@ "name": "ASK_BIOMETRY_REFACTORING_ENABLED", "version": "5.22.0" }, - { - "name": "NOTE_REFACTORING_ENABLED", - "version": "5.23.0" - }, { "name": "NEW_ARTWORK_LOADING", "version": "5.24.0" @@ -59,10 +51,6 @@ "name": "NEW_ATTESTATION_ENABLED", "version": "undefined" }, - { - "name": "TWIN_REFACTORING_ENABLED", - "version": "5.23.0" - }, { "name": "SEND_V2_ENABLED", "version": "5.23.0" diff --git a/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt b/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt index 1bc55396bb..a9d9660b18 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt @@ -1,16 +1,8 @@ package com.tangem.domain.redux -import com.tangem.domain.models.scan.ScanResponse import org.rekotlin.Action sealed interface LegacyAction : Action { - /** - * Initiate an onboarding process. - * For resuming unfinished backup of standard Wallet see - * BackupAction.CheckForUnfinishedBackup, GlobalAction.Onboarding.StartForUnfinishedBackup - */ - data class StartOnboardingProcess(val scanResponse: ScanResponse, val canSkipBackup: Boolean = true) : LegacyAction - data object PrepareDetailsScreen : LegacyAction } \ No newline at end of file diff --git a/features/onboarding-v2/api/src/main/kotlin/com/tangem/features/onboarding/v2/OnboardingV2FeatureToggles.kt b/features/onboarding-v2/api/src/main/kotlin/com/tangem/features/onboarding/v2/OnboardingV2FeatureToggles.kt index dbeb952224..8a3ef86745 100644 --- a/features/onboarding-v2/api/src/main/kotlin/com/tangem/features/onboarding/v2/OnboardingV2FeatureToggles.kt +++ b/features/onboarding-v2/api/src/main/kotlin/com/tangem/features/onboarding/v2/OnboardingV2FeatureToggles.kt @@ -1,8 +1,5 @@ package com.tangem.features.onboarding.v2 interface OnboardingV2FeatureToggles { - val isOnboardingV2Enabled: Boolean val isVisaOnboardingEnabled: Boolean - val isNoteRefactoringEnabled: Boolean - val isTwinRefactoringEnabled: Boolean } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/DefaultOnboardingV2FeatureToggles.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/DefaultOnboardingV2FeatureToggles.kt index 80bbb18b70..9bd61c926e 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/DefaultOnboardingV2FeatureToggles.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/DefaultOnboardingV2FeatureToggles.kt @@ -6,12 +6,6 @@ import javax.inject.Inject internal class DefaultOnboardingV2FeatureToggles @Inject constructor( private val featureTogglesManager: FeatureTogglesManager, ) : OnboardingV2FeatureToggles { - override val isOnboardingV2Enabled: Boolean - get() = featureTogglesManager.isFeatureEnabled("ONBOARDING_CODE_REFACTORING_ENABLED") override val isVisaOnboardingEnabled: Boolean get() = featureTogglesManager.isFeatureEnabled("VISA_ONBOARDING_ENABLED") - override val isNoteRefactoringEnabled: Boolean - get() = featureTogglesManager.isFeatureEnabled("NOTE_REFACTORING_ENABLED") - override val isTwinRefactoringEnabled: Boolean - get() = featureTogglesManager.isFeatureEnabled("TWIN_REFACTORING_ENABLED") } \ No newline at end of file diff --git a/features/onboarding/.gitignore b/features/onboarding/.gitignore deleted file mode 100644 index 42afabfd2a..0000000000 --- a/features/onboarding/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/features/onboarding/build.gradle.kts b/features/onboarding/build.gradle.kts deleted file mode 100644 index 6d048e8c4d..0000000000 --- a/features/onboarding/build.gradle.kts +++ /dev/null @@ -1,64 +0,0 @@ -plugins { - alias(deps.plugins.android.library) - alias(deps.plugins.kotlin.android) - alias(deps.plugins.kotlin.kapt) - alias(deps.plugins.kotlin.serialization) - alias(deps.plugins.hilt.android) - id("configuration") -} - -android { - namespace = "com.tangem.feature.onboarding" -} - -dependencies { - /** Core modules */ - implementation(project(":common")) - implementation(project(":domain:models")) - implementation(project(":core:config-toggles")) - implementation(project(":core:datasource")) - implementation(project(":core:analytics")) - implementation(projects.core.analytics.models) - implementation(project(":core:utils")) - implementation(project(":core:ui")) - implementation(project(":core:res")) - implementation(project(":data:common")) - - /** Tangem libraries */ - implementation(tangemDeps.card.core) - implementation(tangemDeps.card.android) { - exclude(module = "joda-time") - } - - /** AndroidX libraries */ - implementation(deps.androidx.core.ktx) - implementation(deps.androidx.appCompat) - implementation(deps.androidx.fragment.ktx) - implementation(deps.androidx.constraintLayout) - implementation(deps.androidx.activity.compose) - implementation(deps.lifecycle.runtime.ktx) - implementation(deps.lifecycle.common.java8) - implementation(deps.lifecycle.viewModel.ktx) - - /** Compose libraries */ - implementation(deps.compose.material) - implementation(deps.compose.material3) - implementation(deps.compose.animation) - implementation(deps.compose.foundation) - implementation(deps.compose.ui) - implementation(deps.compose.ui.tooling) - implementation(deps.compose.coil) - implementation(deps.compose.shimmer) - - implementation(tangemDeps.card.core) - - /** Other libraries */ - implementation(deps.compose.shimmer) - implementation(deps.kotlin.immutable.collections) - implementation(deps.kotlin.serialization) - implementation(deps.timber) - - /** DI */ - implementation(deps.hilt.android) - kapt(deps.hilt.kapt) -} \ No newline at end of file diff --git a/features/onboarding/src/main/assets/mnemonic/mnemonic_dictionary_en.txt b/features/onboarding/src/main/assets/mnemonic/mnemonic_dictionary_en.txt deleted file mode 100644 index f78ccaf2ce..0000000000 --- a/features/onboarding/src/main/assets/mnemonic/mnemonic_dictionary_en.txt +++ /dev/null @@ -1,2048 +0,0 @@ -abandon -ability -able -about -above -absent -absorb -abstract -absurd -abuse -access -accident -account -accuse -achieve -acid -acoustic -acquire -across -act -action -actor -actress -actual -adapt -add -addict -address -adjust -admit -adult -advance -advice -aerobic -affair -afford -afraid -again -age -agent -agree -ahead -aim -air -airport -aisle -alarm -album -alcohol -alert -alien -all -alley -allow -almost -alone -alpha -already -also -alter -always -amateur -amazing -among -amount -amused -analyst -anchor -ancient -anger -angle -angry -animal -ankle -announce -annual -another -answer -antenna -antique -anxiety -any -apart -apology -appear -apple -approve -april -arch -arctic -area -arena -argue -arm -armed -armor -army -around -arrange -arrest -arrive -arrow -art -artefact -artist -artwork -ask -aspect -assault -asset -assist -assume -asthma -athlete -atom -attack -attend -attitude -attract -auction -audit -august -aunt -author -auto -autumn -average -avocado -avoid -awake -aware -away -awesome -awful -awkward -axis -baby -bachelor -bacon -badge -bag -balance -balcony -ball -bamboo -banana -banner -bar -barely -bargain -barrel -base -basic -basket -battle -beach -bean -beauty -because -become -beef -before -begin -behave -behind -believe -below -belt -bench -benefit -best -betray -better -between -beyond -bicycle -bid -bike -bind -biology -bird -birth -bitter -black -blade -blame -blanket -blast -bleak -bless -blind -blood -blossom -blouse -blue -blur -blush -board -boat -body -boil -bomb -bone -bonus -book -boost -border -boring -borrow -boss -bottom -bounce -box -boy -bracket -brain -brand -brass -brave -bread -breeze -brick -bridge -brief -bright -bring -brisk -broccoli -broken -bronze -broom -brother -brown -brush -bubble -buddy -budget -buffalo -build -bulb -bulk -bullet -bundle -bunker -burden -burger -burst -bus -business -busy -butter -buyer -buzz -cabbage -cabin -cable -cactus -cage -cake -call -calm -camera -camp -can -canal -cancel -candy -cannon -canoe -canvas -canyon -capable -capital -captain -car -carbon -card -cargo -carpet -carry -cart -case -cash -casino -castle -casual -cat -catalog -catch -category -cattle -caught -cause -caution -cave -ceiling -celery -cement -census -century -cereal -certain -chair -chalk -champion -change -chaos -chapter -charge -chase -chat -cheap -check -cheese -chef -cherry -chest -chicken -chief -child -chimney -choice -choose -chronic -chuckle -chunk -churn -cigar -cinnamon -circle -citizen -city -civil -claim -clap -clarify -claw -clay -clean -clerk -clever -click -client -cliff -climb -clinic -clip -clock -clog -close -cloth -cloud -clown -club -clump -cluster -clutch -coach -coast -coconut -code -coffee -coil -coin -collect -color -column -combine -come -comfort -comic -common -company -concert -conduct -confirm -congress -connect -consider -control -convince -cook -cool -copper -copy -coral -core -corn -correct -cost -cotton -couch -country -couple -course -cousin -cover -coyote -crack -cradle -craft -cram -crane -crash -crater -crawl -crazy -cream -credit -creek -crew -cricket -crime -crisp -critic -crop -cross -crouch -crowd -crucial -cruel -cruise -crumble -crunch -crush -cry -crystal -cube -culture -cup -cupboard -curious -current -curtain -curve -cushion -custom -cute -cycle -dad -damage -damp -dance -danger -daring -dash -daughter -dawn -day -deal -debate -debris -decade -december -decide -decline -decorate -decrease -deer -defense -define -defy -degree -delay -deliver -demand -demise -denial -dentist -deny -depart -depend -deposit -depth -deputy -derive -describe -desert -design -desk -despair -destroy -detail -detect -develop -device -devote -diagram -dial -diamond -diary -dice -diesel -diet -differ -digital -dignity -dilemma -dinner -dinosaur -direct -dirt -disagree -discover -disease -dish -dismiss -disorder -display -distance -divert -divide -divorce -dizzy -doctor -document -dog -doll -dolphin -domain -donate -donkey -donor -door -dose -double -dove -draft -dragon -drama -drastic -draw -dream -dress -drift -drill -drink -drip -drive -drop -drum -dry -duck -dumb -dune -during -dust -dutch -duty -dwarf -dynamic -eager -eagle -early -earn -earth -easily -east -easy -echo -ecology -economy -edge -edit -educate -effort -egg -eight -either -elbow -elder -electric -elegant -element -elephant -elevator -elite -else -embark -embody -embrace -emerge -emotion -employ -empower -empty -enable -enact -end -endless -endorse -enemy -energy -enforce -engage -engine -enhance -enjoy -enlist -enough -enrich -enroll -ensure -enter -entire -entry -envelope -episode -equal -equip -era -erase -erode -erosion -error -erupt -escape -essay -essence -estate -eternal -ethics -evidence -evil -evoke -evolve -exact -example -excess -exchange -excite -exclude -excuse -execute -exercise -exhaust -exhibit -exile -exist -exit -exotic -expand -expect -expire -explain -expose -express -extend -extra -eye -eyebrow -fabric -face -faculty -fade -faint -faith -fall -false -fame -family -famous -fan -fancy -fantasy -farm -fashion -fat -fatal -father -fatigue -fault -favorite -feature -february -federal -fee -feed -feel -female -fence -festival -fetch -fever -few -fiber -fiction -field -figure -file -film -filter -final -find -fine -finger -finish -fire -firm -first -fiscal -fish -fit -fitness -fix -flag -flame -flash -flat -flavor -flee -flight -flip -float -flock -floor -flower -fluid -flush -fly -foam -focus -fog -foil -fold -follow -food -foot -force -forest -forget -fork -fortune -forum -forward -fossil -foster -found -fox -fragile -frame -frequent -fresh -friend -fringe -frog -front -frost -frown -frozen -fruit -fuel -fun -funny -furnace -fury -future -gadget -gain -galaxy -gallery -game -gap -garage -garbage -garden -garlic -garment -gas -gasp -gate -gather -gauge -gaze -general -genius -genre -gentle -genuine -gesture -ghost -giant -gift -giggle -ginger -giraffe -girl -give -glad -glance -glare -glass -glide -glimpse -globe -gloom -glory -glove -glow -glue -goat -goddess -gold -good -goose -gorilla -gospel -gossip -govern -gown -grab -grace -grain -grant -grape -grass -gravity -great -green -grid -grief -grit -grocery -group -grow -grunt -guard -guess -guide -guilt -guitar -gun -gym -habit -hair -half -hammer -hamster -hand -happy -harbor -hard -harsh -harvest -hat -have -hawk -hazard -head -health -heart -heavy -hedgehog -height -hello -helmet -help -hen -hero -hidden -high -hill -hint -hip -hire -history -hobby -hockey -hold -hole -holiday -hollow -home -honey -hood -hope -horn -horror -horse -hospital -host -hotel -hour -hover -hub -huge -human -humble -humor -hundred -hungry -hunt -hurdle -hurry -hurt -husband -hybrid -ice -icon -idea -identify -idle -ignore -ill -illegal -illness -image -imitate -immense -immune -impact -impose -improve -impulse -inch -include -income -increase -index -indicate -indoor -industry -infant -inflict -inform -inhale -inherit -initial -inject -injury -inmate -inner -innocent -input -inquiry -insane -insect -inside -inspire -install -intact -interest -into -invest -invite -involve -iron -island -isolate -issue -item -ivory -jacket -jaguar -jar -jazz -jealous -jeans -jelly -jewel -job -join -joke -journey -joy -judge -juice -jump -jungle -junior -junk -just -kangaroo -keen -keep -ketchup -key -kick -kid -kidney -kind -kingdom -kiss -kit -kitchen -kite -kitten -kiwi -knee -knife -knock -know -lab -label -labor -ladder -lady -lake -lamp -language -laptop -large -later -latin -laugh -laundry -lava -law -lawn -lawsuit -layer -lazy -leader -leaf -learn -leave -lecture -left -leg -legal -legend -leisure -lemon -lend -length -lens -leopard -lesson -letter -level -liar -liberty -library -license -life -lift -light -like -limb -limit -link -lion -liquid -list -little -live -lizard -load -loan -lobster -local -lock -logic -lonely -long -loop -lottery -loud -lounge -love -loyal -lucky -luggage -lumber -lunar -lunch -luxury -lyrics -machine -mad -magic -magnet -maid -mail -main -major -make -mammal -man -manage -mandate -mango -mansion -manual -maple -marble -march -margin -marine -market -marriage -mask -mass -master -match -material -math -matrix -matter -maximum -maze -meadow -mean -measure -meat -mechanic -medal -media -melody -melt -member -memory -mention -menu -mercy -merge -merit -merry -mesh -message -metal -method -middle -midnight -milk -million -mimic -mind -minimum -minor -minute -miracle -mirror -misery -miss -mistake -mix -mixed -mixture -mobile -model -modify -mom -moment -monitor -monkey -monster -month -moon -moral -more -morning -mosquito -mother -motion -motor -mountain -mouse -move -movie -much -muffin -mule -multiply -muscle -museum -mushroom -music -must -mutual -myself -mystery -myth -naive -name -napkin -narrow -nasty -nation -nature -near -neck -need -negative -neglect -neither -nephew -nerve -nest -net -network -neutral -never -news -next -nice -night -noble -noise -nominee -noodle -normal -north -nose -notable -note -nothing -notice -novel -now -nuclear -number -nurse -nut -oak -obey -object -oblige -obscure -observe -obtain -obvious -occur -ocean -october -odor -off -offer -office -often -oil -okay -old -olive -olympic -omit -once -one -onion -online -only -open -opera -opinion -oppose -option -orange -orbit -orchard -order -ordinary -organ -orient -original -orphan -ostrich -other -outdoor -outer -output -outside -oval -oven -over -own -owner -oxygen -oyster -ozone -pact -paddle -page -pair -palace -palm -panda -panel -panic -panther -paper -parade -parent -park -parrot -party -pass -patch -path -patient -patrol -pattern -pause -pave -payment -peace -peanut -pear -peasant -pelican -pen -penalty -pencil -people -pepper -perfect -permit -person -pet -phone -photo -phrase -physical -piano -picnic -picture -piece -pig -pigeon -pill -pilot -pink -pioneer -pipe -pistol -pitch -pizza -place -planet -plastic -plate -play -please -pledge -pluck -plug -plunge -poem -poet -point -polar -pole -police -pond -pony -pool -popular -portion -position -possible -post -potato -pottery -poverty -powder -power -practice -praise -predict -prefer -prepare -present -pretty -prevent -price -pride -primary -print -priority -prison -private -prize -problem -process -produce -profit -program -project -promote -proof -property -prosper -protect -proud -provide -public -pudding -pull -pulp -pulse -pumpkin -punch -pupil -puppy -purchase -purity -purpose -purse -push -put -puzzle -pyramid -quality -quantum -quarter -question -quick -quit -quiz -quote -rabbit -raccoon -race -rack -radar -radio -rail -rain -raise -rally -ramp -ranch -random -range -rapid -rare -rate -rather -raven -raw -razor -ready -real -reason -rebel -rebuild -recall -receive -recipe -record -recycle -reduce -reflect -reform -refuse -region -regret -regular -reject -relax -release -relief -rely -remain -remember -remind -remove -render -renew -rent -reopen -repair -repeat -replace -report -require -rescue -resemble -resist -resource -response -result -retire -retreat -return -reunion -reveal -review -reward -rhythm -rib -ribbon -rice -rich -ride -ridge -rifle -right -rigid -ring -riot -ripple -risk -ritual -rival -river -road -roast -robot -robust -rocket -romance -roof -rookie -room -rose -rotate -rough -round -route -royal -rubber -rude -rug -rule -run -runway -rural -sad -saddle -sadness -safe -sail -salad -salmon -salon -salt -salute -same -sample -sand -satisfy -satoshi -sauce -sausage -save -say -scale -scan -scare -scatter -scene -scheme -school -science -scissors -scorpion -scout -scrap -screen -script -scrub -sea -search -season -seat -second -secret -section -security -seed -seek -segment -select -sell -seminar -senior -sense -sentence -series -service -session -settle -setup -seven -shadow -shaft -shallow -share -shed -shell -sheriff -shield -shift -shine -ship -shiver -shock -shoe -shoot -shop -short -shoulder -shove -shrimp -shrug -shuffle -shy -sibling -sick -side -siege -sight -sign -silent -silk -silly -silver -similar -simple -since -sing -siren -sister -situate -six -size -skate -sketch -ski -skill -skin -skirt -skull -slab -slam -sleep -slender -slice -slide -slight -slim -slogan -slot -slow -slush -small -smart -smile -smoke -smooth -snack -snake -snap -sniff -snow -soap -soccer -social -sock -soda -soft -solar -soldier -solid -solution -solve -someone -song -soon -sorry -sort -soul -sound -soup -source -south -space -spare -spatial -spawn -speak -special -speed -spell -spend -sphere -spice -spider -spike -spin -spirit -split -spoil -sponsor -spoon -sport -spot -spray -spread -spring -spy -square -squeeze -squirrel -stable -stadium -staff -stage -stairs -stamp -stand -start -state -stay -steak -steel -stem -step -stereo -stick -still -sting -stock -stomach -stone -stool -story -stove -strategy -street -strike -strong -struggle -student -stuff -stumble -style -subject -submit -subway -success -such -sudden -suffer -sugar -suggest -suit -summer -sun -sunny -sunset -super -supply -supreme -sure -surface -surge -surprise -surround -survey -suspect -sustain -swallow -swamp -swap -swarm -swear -sweet -swift -swim -swing -switch -sword -symbol -symptom -syrup -system -table -tackle -tag -tail -talent -talk -tank -tape -target -task -taste -tattoo -taxi -teach -team -tell -ten -tenant -tennis -tent -term -test -text -thank -that -theme -then -theory -there -they -thing -this -thought -three -thrive -throw -thumb -thunder -ticket -tide -tiger -tilt -timber -time -tiny -tip -tired -tissue -title -toast -tobacco -today -toddler -toe -together -toilet -token -tomato -tomorrow -tone -tongue -tonight -tool -tooth -top -topic -topple -torch -tornado -tortoise -toss -total -tourist -toward -tower -town -toy -track -trade -traffic -tragic -train -transfer -trap -trash -travel -tray -treat -tree -trend -trial -tribe -trick -trigger -trim -trip -trophy -trouble -truck -true -truly -trumpet -trust -truth -try -tube -tuition -tumble -tuna -tunnel -turkey -turn -turtle -twelve -twenty -twice -twin -twist -two -type -typical -ugly -umbrella -unable -unaware -uncle -uncover -under -undo -unfair -unfold -unhappy -uniform -unique -unit -universe -unknown -unlock -until -unusual -unveil -update -upgrade -uphold -upon -upper -upset -urban -urge -usage -use -used -useful -useless -usual -utility -vacant -vacuum -vague -valid -valley -valve -van -vanish -vapor -various -vast -vault -vehicle -velvet -vendor -venture -venue -verb -verify -version -very -vessel -veteran -viable -vibrant -vicious -victory -video -view -village -vintage -violin -virtual -virus -visa -visit -visual -vital -vivid -vocal -voice -void -volcano -volume -vote -voyage -wage -wagon -wait -walk -wall -walnut -want -warfare -warm -warrior -wash -wasp -waste -water -wave -way -wealth -weapon -wear -weasel -weather -web -wedding -weekend -weird -welcome -west -wet -whale -what -wheat -wheel -when -where -whip -whisper -wide -width -wife -wild -will -win -window -wine -wing -wink -winner -winter -wire -wisdom -wise -wish -witness -wolf -woman -wonder -wood -wool -word -work -world -worry -worth -wrap -wreck -wrestle -wrist -write -wrong -yard -year -yellow -you -young -youth -zebra -zero -zone -zoo \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseApi.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseApi.kt deleted file mode 100644 index 43ac6afa71..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseApi.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.feature.onboarding.api - -import androidx.compose.runtime.Composable -import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen - -/** -[REDACTED_AUTHOR] - */ -interface OnboardingSeedPhraseApi { - @Suppress("TopLevelComposableFunctions") - @Composable - fun ScreenContent(uiState: OnboardingSeedPhraseState, subScreen: SeedPhraseScreen, progress: Float) -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt deleted file mode 100644 index 51d9740d8c..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.tangem.feature.onboarding.api - -import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.StrokeCap -import com.tangem.core.ui.components.progressbar.TangemLinearProgressIndicator -import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState -import com.tangem.feature.onboarding.presentation.wallet2.ui.* -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen - -/** -[REDACTED_AUTHOR] - */ -class OnboardingSeedPhraseScreen : OnboardingSeedPhraseApi { - - @Composable - override fun ScreenContent(uiState: OnboardingSeedPhraseState, subScreen: SeedPhraseScreen, progress: Float) { - BackHandler(onBack = uiState.onBackClick) - Column { - TangemLinearProgressIndicator( - progress = { progress }, - color = TangemTheme.colors.icon.primary1, - backgroundColor = TangemTheme.colors.icon.primary1.copy(alpha = 0.4f), - strokeCap = StrokeCap.Round, - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(top = TangemTheme.dimens.size8) - .padding(horizontal = TangemTheme.dimens.size16), - ) - Content(subScreen, uiState) - } - } -} - -@Composable -private fun Content(screen: SeedPhraseScreen, uiState: OnboardingSeedPhraseState) { - when (screen) { - SeedPhraseScreen.Intro -> { - IntroScreen( - state = uiState.introState, - ) - } - SeedPhraseScreen.AboutSeedPhrase -> { - AboutSeedPhraseScreen( - state = uiState.aboutState, - ) - } - SeedPhraseScreen.YourSeedPhrase -> { - YourSeedPhraseScreen( - state = uiState.yourSeedPhraseState, - ) - } - SeedPhraseScreen.CheckSeedPhrase -> { - CheckSeedPhraseScreen( - state = uiState.checkSeedPhraseState, - ) - } - SeedPhraseScreen.ImportSeedPhrase -> { - ImportSeedPhraseScreen( - state = uiState.importSeedPhraseState, - ) - } - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt deleted file mode 100644 index 09bc1f8964..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/DefaultMnemonicRepository.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.tangem.feature.onboarding.data - -import com.tangem.crypto.bip39.DefaultMnemonic -import com.tangem.crypto.bip39.EntropyLength -import com.tangem.crypto.bip39.Mnemonic -import com.tangem.crypto.bip39.Wordlist -import com.tangem.feature.onboarding.domain.models.MnemonicType - -/** -[REDACTED_AUTHOR] - */ -class DefaultMnemonicRepository( - private val bip39Wordlist: Wordlist, -) : MnemonicRepository { - - private val bip39Words: Set by lazy { bip39Wordlist.words.toHashSet() } - - override fun getWordsDictionary(): Set = bip39Words - - override fun generateDefaultMnemonic(): Mnemonic { - return DefaultMnemonic(EntropyLength.Bits128Length, bip39Wordlist) - } - - override fun generateMnemonic(mnemonicType: MnemonicType): Mnemonic { - return when (mnemonicType) { - MnemonicType.Mnemonic12 -> DefaultMnemonic(EntropyLength.Bits128Length, bip39Wordlist) - MnemonicType.Mnemonic24 -> DefaultMnemonic(EntropyLength.Bits256Length, bip39Wordlist) - } - } - - override fun createMnemonic(mnemonicString: String): Mnemonic = DefaultMnemonic(mnemonicString, bip39Wordlist) -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/MnemonicRepository.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/MnemonicRepository.kt deleted file mode 100644 index 389ca4d949..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/MnemonicRepository.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.tangem.feature.onboarding.data - -import com.tangem.common.core.TangemSdkError -import com.tangem.crypto.bip39.Mnemonic -import com.tangem.feature.onboarding.domain.models.MnemonicType - -/** -[REDACTED_AUTHOR] - */ -interface MnemonicRepository { - - fun getWordsDictionary(): Set - - @Throws(TangemSdkError.MnemonicException::class) - fun generateDefaultMnemonic(): Mnemonic - - @Throws(TangemSdkError.MnemonicException::class) - fun generateMnemonic(mnemonicType: MnemonicType): Mnemonic - - @Throws(TangemSdkError.MnemonicException::class) - fun createMnemonic(mnemonicString: String): Mnemonic -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/model/CreateWalletResponse.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/model/CreateWalletResponse.kt deleted file mode 100644 index 76f4027a1b..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/data/model/CreateWalletResponse.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.feature.onboarding.data.model - -import com.tangem.common.extensions.ByteArrayKey -import com.tangem.domain.models.scan.CardDTO -import com.tangem.operations.backup.PrimaryCard -import com.tangem.operations.derivation.ExtendedPublicKeysMap - -/** -[REDACTED_AUTHOR] - */ -data class CreateWalletResponse( - val card: CardDTO, - val derivedKeys: Map = mapOf(), - val primaryCard: PrimaryCard? = null, -) \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/di/OnboardingRouterModule.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/di/OnboardingRouterModule.kt deleted file mode 100644 index acc54e7b9b..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/di/OnboardingRouterModule.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.tangem.feature.onboarding.di - -import com.tangem.feature.onboarding.navigation.DefaultOnboardingRouter -import com.tangem.feature.onboarding.navigation.OnboardingRouter -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.scopes.ActivityScoped - -@Module -@InstallIn(ActivityComponent::class) -internal object OnboardingRouterModule { - - @Provides - @ActivityScoped - fun provideOnboardingRouter(): OnboardingRouter { - return DefaultOnboardingRouter() - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/DefaultSeedPhraseInteractor.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/DefaultSeedPhraseInteractor.kt deleted file mode 100644 index a0ef98bf30..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/DefaultSeedPhraseInteractor.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.tangem.feature.onboarding.domain - -import com.tangem.common.core.TangemSdkError -import com.tangem.crypto.bip39.Mnemonic -import com.tangem.crypto.bip39.MnemonicErrorResult -import com.tangem.feature.onboarding.data.MnemonicRepository -import com.tangem.feature.onboarding.domain.models.MnemonicType -import com.tangem.feature.onboarding.presentation.wallet2.model.SeedPhraseField -import com.tangem.utils.extensions.isNotWhitespace -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toPersistentList - -/** -[REDACTED_AUTHOR] - */ -internal class DefaultSeedPhraseInteractor( - private val repository: MnemonicRepository, -) : SeedPhraseInteractor { - - private val partWordFinder: PartWordFinder = PartWordFinder() - - override suspend fun generateMnemonic(): Result { - return runCatching { - repository.generateDefaultMnemonic() - } - } - - override suspend fun generateMnemonics(mnemonicTypes: List): Result> { - return runCatching { - mnemonicTypes.associateWith { - repository.generateMnemonic(it) - } - } - } - - override suspend fun isWordMatch(mnemonicComponents: List?, field: SeedPhraseField, word: String): Boolean { - return mnemonicComponents?.get(field.index) == word - } - - override suspend fun validateMnemonicString(text: String): Result> { - val inputWords = text.split("\\s+".toRegex()).toSet() - val wordsDictionary = repository.getWordsDictionary() - - val invalidWords = inputWords - .filter { it.isNotEmpty() && !wordsDictionary.contains(it) } - .toSet() - - return if (invalidWords.isNotEmpty()) { - Result.failure(SeedPhraseError.InvalidWords(invalidWords)) - } else { - try { - val mnemonic = repository.createMnemonic(text) - Result.success(mnemonic.mnemonicComponents) - } catch (ex: TangemSdkError.MnemonicException) { - val error = ex.mnemonicResult.mapToError() - Result.failure(error) - } - } - } - - override suspend fun getSuggestions( - text: String, - hasSelection: Boolean, - cursorPosition: Int, - ): ImmutableList { - if (text.isEmpty() || cursorPosition == 0 || hasSelection) return persistentListOf() - val word = partWordFinder.getLeadPartOfWord(text, cursorPosition) - ?: return persistentListOf() - - val suggestions = repository.getWordsDictionary() - .filter { it.startsWith(word, ignoreCase = false) && it != word } - .toPersistentList() - - return suggestions - } - - override suspend fun insertSuggestionWord( - text: String, - suggestion: String, - cursorPosition: Int, - ): InsertSuggestionResult { - val textPartLead = text.substring(0, cursorPosition) - val textPartLast = text.substring(cursorPosition, text.length) - val wordPartLast = partWordFinder.getLastPartOfWord(text, suggestion, cursorPosition) - - val textBuilder = StringBuilder() - .append(textPartLead) - .append(wordPartLast) - - if (textPartLast.isEmpty() || textPartLast[0].isNotWhitespace()) { - textBuilder.append(SeedPhraseInteractor.MNEMONIC_DELIMITER) - } - textBuilder.append(textPartLast) - - val textWithSuggestion = textBuilder.toString() - val newCursorPosition = cursorPosition + wordPartLast.length + SeedPhraseInteractor.MNEMONIC_DELIMITER.length - - return InsertSuggestionResult(textWithSuggestion, newCursorPosition) - } -} - -private fun MnemonicErrorResult.mapToError(): SeedPhraseError = when (this) { - MnemonicErrorResult.InvalidWordCount -> SeedPhraseError.InvalidWordCount - MnemonicErrorResult.InvalidEntropyLength -> SeedPhraseError.InvalidEntropyLength - MnemonicErrorResult.InvalidWordsFile -> SeedPhraseError.InvalidWordsFile - MnemonicErrorResult.InvalidChecksum -> SeedPhraseError.InvalidChecksum - MnemonicErrorResult.MnenmonicCreationFailed -> SeedPhraseError.MnenmonicCreationFailed - MnemonicErrorResult.NormalizationFailed -> SeedPhraseError.NormalizationFailed - MnemonicErrorResult.UnsupportedLanguage -> SeedPhraseError.UnsupportedLanguage - is MnemonicErrorResult.InvalidWords -> SeedPhraseError.InvalidWords(this.words) - MnemonicErrorResult.InvalidMnemonic -> SeedPhraseError.InvalidMnemonic -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/OnboardingModuleError.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/OnboardingModuleError.kt deleted file mode 100644 index e36bc935bd..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/OnboardingModuleError.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.tangem.feature.onboarding.domain - -import com.tangem.common.module.ModuleError -import com.tangem.common.module.ModuleErrorCode -import com.tangem.common.module.ModuleMessage - -/** -[REDACTED_AUTHOR] - * For each pool of errors, use the codes lying in range 100 (200..299, 300..399, etc) - */ -abstract class OnboardingModuleError( - subCode: Int, - override val message: String, - override val data: Any?, -) : ModuleMessage, ModuleError() { - override val code: Int = ModuleErrorCode.ONBOARDING + subCode - - companion object { - internal const val ERROR_CODE_SEED_PHRASE = 100 - } -} - -sealed class SeedPhraseError( - subCode: Int = 0, - message: String? = null, - data: Any? = null, -) : OnboardingModuleError( - subCode = ERROR_CODE_SEED_PHRASE + subCode, - message = message ?: this::class.java.simpleName, - data = data, -) { - object InvalidWordCount : SeedPhraseError(subCode = 0) - object InvalidEntropyLength : SeedPhraseError(subCode = 1) - object InvalidWordsFile : SeedPhraseError(subCode = 2) - object InvalidChecksum : SeedPhraseError(subCode = 3) - object MnenmonicCreationFailed : SeedPhraseError(subCode = 4) - object NormalizationFailed : SeedPhraseError(subCode = 5) - object UnsupportedLanguage : SeedPhraseError(subCode = 6) - data class InvalidWords(val words: Set) : SeedPhraseError(subCode = 7) - object InvalidMnemonic : SeedPhraseError(subCode = 8) -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/PartWordFinder.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/PartWordFinder.kt deleted file mode 100644 index 97ca9cd8d9..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/PartWordFinder.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.tangem.feature.onboarding.domain - -import com.tangem.utils.extensions.isNotWhitespace - -/** -[REDACTED_AUTHOR] - * Class which provides helper functions to determine lead or last part of words for suggestions - */ -internal class PartWordFinder { - - /** - * Searches and return part of a word on the left side of the [cursorPosition] into the [text] - */ - fun getLeadPartOfWord(text: String, cursorPosition: Int): String? { - val charText = text.toCharArray().asList() - val cursorIsOutOfTextRange = cursorPosition > charText.size || cursorPosition < 0 - val cursorAtStartOfText = cursorPosition == 0 - val hadWhiteSpaceOnLeftOfCursor = charText[cursorPosition - 1].isWhitespace() - val cursorInMiddleOfWord = charText.size > cursorPosition && charText[cursorPosition].isNotWhitespace() - - @Suppress("ComplexCondition") - if (cursorIsOutOfTextRange || cursorAtStartOfText || hadWhiteSpaceOnLeftOfCursor || cursorInMiddleOfWord) { - return null - } - - for (charIndex in cursorPosition - 1 downTo 0) { - val char = charText[charIndex] - when { - charIndex == 0 -> { - return text.substring(charIndex, cursorPosition) - } - char.isWhitespace() -> { - return text.substring(charIndex + 1, cursorPosition) - } - } - } - - return null - } - - /** - * Returns a substring of the [word] which excludes the first word part found on the left of [cursorPosition] in - * the [text] - */ - fun getLastPartOfWord(text: String, word: String, cursorPosition: Int): String { - val leadPart = getLeadPartOfWord(text, cursorPosition) ?: return "" - - return word.substring(leadPart.length, word.length) - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/SeedPhraseInteractor.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/SeedPhraseInteractor.kt deleted file mode 100644 index 37e0c182da..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/SeedPhraseInteractor.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.feature.onboarding.domain - -import com.tangem.crypto.bip39.Mnemonic -import com.tangem.feature.onboarding.domain.models.MnemonicType -import com.tangem.feature.onboarding.presentation.wallet2.model.SeedPhraseField -import kotlinx.collections.immutable.ImmutableList - -/** -[REDACTED_AUTHOR] - */ -interface SeedPhraseInteractor { - suspend fun generateMnemonic(): Result - suspend fun generateMnemonics(mnemonicTypes: List): Result> - suspend fun isWordMatch(mnemonicComponents: List?, field: SeedPhraseField, word: String): Boolean - suspend fun validateMnemonicString(text: String): Result> - suspend fun getSuggestions(text: String, hasSelection: Boolean, cursorPosition: Int): ImmutableList - suspend fun insertSuggestionWord(text: String, suggestion: String, cursorPosition: Int): InsertSuggestionResult - - companion object { - const val MNEMONIC_DELIMITER = " " - } -} - -data class InsertSuggestionResult( - val text: String, - val cursorPosition: Int, -) \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/di/OnboardingDomainModule.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/di/OnboardingDomainModule.kt deleted file mode 100644 index 108700efe3..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/di/OnboardingDomainModule.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.feature.onboarding.domain.di - -import com.tangem.feature.onboarding.data.MnemonicRepository -import com.tangem.feature.onboarding.domain.DefaultSeedPhraseInteractor -import com.tangem.feature.onboarding.domain.SeedPhraseInteractor -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -class OnboardingDomainModule { - - @Provides - @Singleton - fun provideSeedPhraseInteractor(repository: MnemonicRepository): SeedPhraseInteractor { - return DefaultSeedPhraseInteractor(repository) - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/models/MnemonicType.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/models/MnemonicType.kt deleted file mode 100644 index ea4a74f87f..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/domain/models/MnemonicType.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.feature.onboarding.domain.models - -enum class MnemonicType { - Mnemonic12, Mnemonic24; -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/DefaultOnboardingRouter.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/DefaultOnboardingRouter.kt deleted file mode 100644 index 0d34ac7cd3..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/DefaultOnboardingRouter.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.tangem.feature.onboarding.navigation - -class DefaultOnboardingRouter : OnboardingRouter \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/OnboardingRouter.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/OnboardingRouter.kt deleted file mode 100644 index b6bf1b0f60..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/navigation/OnboardingRouter.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.tangem.feature.onboarding.navigation - -/** - * Onboarding router - */ -// TODO: Move to onboarding api module [REDACTED_JIRA] -interface OnboardingRouter \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/analytics/SeedPhraseEvents.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/analytics/SeedPhraseEvents.kt deleted file mode 100644 index 9ae8093ab2..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/analytics/SeedPhraseEvents.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.analytics - -import com.tangem.core.analytics.models.AnalyticsEvent - -sealed class SeedPhraseEvents( - event: String, - params: Map = mapOf(), -) : AnalyticsEvent(ONBOARDING_SEED_PHRASE, event, params) { - - object ButtonGenerateSeedPhrase : SeedPhraseEvents("Button - Generate Seed Phrase") - - object ButtonImportWallet : SeedPhraseEvents("Button - Import Wallet") - object ButtonReadMore : SeedPhraseEvents("Button - Read More") - object ButtonImport : SeedPhraseEvents("Button - Import") - - object IntroScreenOpened : SeedPhraseEvents("Seed Intro Screen Opened") - object GenerationScreenOpened : SeedPhraseEvents("Seed Generation Screen Opened") - object CheckingScreenOpened : SeedPhraseEvents("Seed Checking Screen Opened") - object ImportScreenOpened : SeedPhraseEvents("Import Seed Phrase Screen Opened") - - companion object { - const val ONBOARDING_SEED_PHRASE = "Onboarding / Seed Phrase" - } -} - -sealed class CreateWalletEvents( - event: String, - params: Map = mapOf(), -) : AnalyticsEvent(ONBOARDING_CREATE_WALLET, event, params) { - - object OnboardingSeedButtonCreateWallet : CreateWalletEvents("Button - Create Wallet") - - object OnboardingSeedButtonOtherOptions : CreateWalletEvents("Button - Other Options") - companion object { - const val ONBOARDING_CREATE_WALLET = "Onboarding / Create Wallet" - } -} - -enum class SeedPhraseSource { - IMPORTED, GENERATED -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/ButtonState.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/ButtonState.kt deleted file mode 100644 index 842a7a5141..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/ButtonState.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.model - -/** -[REDACTED_AUTHOR] - */ -data class ButtonState( - val enabled: Boolean = true, - val isClickable: Boolean = true, - val showProgress: Boolean = false, - val onClick: () -> Unit, -) \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/DescriptionResource.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/DescriptionResource.kt deleted file mode 100644 index db8f0d469b..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/DescriptionResource.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.model - -import androidx.annotation.StringRes - -data class DescriptionResource( - @StringRes val titleRes: Int, - @StringRes val subTitleRes: Int, -) \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/OnboardingSeedPhraseState.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/OnboardingSeedPhraseState.kt deleted file mode 100644 index a8300c9a76..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/OnboardingSeedPhraseState.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.model - -import androidx.compose.ui.text.input.TextFieldValue -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.feature.onboarding.domain.SeedPhraseError -import com.tangem.feature.onboarding.domain.models.MnemonicType -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.persistentListOf - -/** -[REDACTED_AUTHOR] - */ -data class OnboardingSeedPhraseState( - val introState: IntroState, - val aboutState: AboutState, - val yourSeedPhraseState: YourSeedPhraseState, - val checkSeedPhraseState: CheckSeedPhraseState, - val importSeedPhraseState: ImportSeedPhraseState, - val menuButtonChat: ButtonState, - val onBackClick: () -> Unit, -) - -data class IntroState( - val cardImageUrl: String? = null, - val buttonCreateWallet: ButtonState, - val buttonOtherOptions: ButtonState, -) - -data class AboutState( - val buttonReadMoreAboutSeedPhrase: ButtonState, - val buttonGenerateSeedPhrase: ButtonState, - val buttonImportSeedPhrase: ButtonState, -) - -data class YourSeedPhraseState( - val segmentSeedState: SegmentSeedState, - val mnemonicGridItems: PersistentList = persistentListOf(), - val buttonContinue: ButtonState, -) - -data class SegmentSeedState( - val seedSegments: PersistentList, - val selectedSeedType: SegmentSeedType, - val onSelectType: (SegmentSeedType) -> Unit, -) - -enum class SegmentSeedType(val count: Int) { - SEED_12(count = 12), SEED_24(count = 24); - - fun toMnemonicType(): MnemonicType { - return when (this) { - SEED_12 -> MnemonicType.Mnemonic12 - SEED_24 -> MnemonicType.Mnemonic24 - } - } - - companion object { - fun fromMnemonicType(mnemonicType: MnemonicType): SegmentSeedType { - return when (mnemonicType) { - MnemonicType.Mnemonic12 -> SEED_12 - MnemonicType.Mnemonic24 -> SEED_24 - } - } - } -} - -data class MnemonicGridItem( - val index: Int, - val mnemonic: String, -) - -data class CheckSeedPhraseState( - val tvSecondPhrase: TextFieldState, - val tvSeventhPhrase: TextFieldState, - val tvEleventhPhrase: TextFieldState, - val buttonCreateWallet: ButtonState, -) - -data class ImportSeedPhraseState( - val fieldSeedPhrase: TextFieldState, - val fieldPassphrase: TextFieldState, - val onSuggestedPhraseClick: (Int) -> Unit, - val onPassphraseInfoClick: () -> Unit, - val buttonCreateWallet: ButtonState, - val invalidWords: Set = emptySet(), - val suggestionsList: ImmutableList = persistentListOf(), - val error: SeedPhraseError? = null, - val bottomSheetConfig: TangemBottomSheetConfig? = null, -) - -data class ShowPassphraseInfoBottomSheetContent(val onOkClick: () -> Unit) : TangemBottomSheetConfigContent - -data class TextFieldState( - val onTextFieldValueChanged: (TextFieldValue) -> Unit, - val textFieldValue: TextFieldValue = TextFieldValue(), - val label: String? = null, - val isError: Boolean = false, - val isFocused: Boolean = false, - val onFocusChanged: (Boolean) -> Unit = {}, -) \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/UiActions.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/UiActions.kt deleted file mode 100644 index 91db0f6407..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/model/UiActions.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.model - -import androidx.compose.ui.text.input.TextFieldValue - -/** -[REDACTED_AUTHOR] - */ -data class UiActions( - val introActions: IntroUiAction, - val aboutActions: AboutUiAction, - val yourSeedPhraseActions: YourSeedPhraseUiAction, - val checkSeedPhraseActions: CheckSeedPhraseUiAction, - val importSeedPhraseActions: ImportSeedPhraseUiAction, - val menuChatClick: () -> Unit, - val menuNavigateBackClick: () -> Unit, -) - -data class IntroUiAction( - val buttonCreateWalletClick: () -> Unit, - val buttonOtherOptionsClick: () -> Unit, -) - -data class AboutUiAction( - val buttonReadMoreAboutSeedPhraseClick: () -> Unit, - val buttonGenerateSeedPhraseClick: () -> Unit, - val buttonImportSeedPhraseClick: () -> Unit, -) - -data class YourSeedPhraseUiAction( - val buttonContinueClick: () -> Unit, - val onSelectType: (SegmentSeedType) -> Unit, -) - -data class CheckSeedPhraseUiAction( - val secondTextFieldAction: TextFieldUiAction, - val seventhTextFieldAction: TextFieldUiAction, - val eleventhTextFieldAction: TextFieldUiAction, - val buttonCreateWalletClick: () -> Unit, -) - -data class ImportSeedPhraseUiAction( - val phraseTextFieldAction: TextFieldUiAction, - val passTextFieldAction: TextFieldUiAction, - val suggestedPhraseClick: (Int) -> Unit, - val onPassphraseInfoClick: () -> Unit, - val buttonCreateWalletClick: () -> Unit, -) - -data class TextFieldUiAction( - val onTextFieldChanged: (TextFieldValue) -> Unit, - val onFocusChanged: (Boolean) -> Unit = {}, -) - - - -enum class SeedPhraseField(val index: Int) { - Second(index = 1), - Seventh(index = 6), - Eleventh(index = 10), -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt deleted file mode 100644 index e0cab80df9..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui - -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.painterResource -import com.tangem.core.ui.components.SecondaryButton -import com.tangem.core.ui.components.SpacerH32 -import com.tangem.core.ui.components.SpacerW8 -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.onboarding.R -import com.tangem.feature.onboarding.presentation.wallet2.model.AboutState -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.Description -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingActionBlock -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingDescriptionBlock - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun AboutSeedPhraseScreen(state: AboutState, modifier: Modifier = Modifier) { - Column( - modifier = modifier.fillMaxSize(), - ) { - Box( - modifier = Modifier.weight(weight = 0.8f), - ) { - EditIconBlock() - } - Box( - modifier = Modifier.weight(weight = 1.2f), - ) { - Column { - OnboardingDescriptionBlock { - Description( - titleRes = R.string.onboarding_seed_intro_title, - subTitleRes = R.string.onboarding_seed_intro_message, - ) - } - ReadMoreBlock(state) - } - } - Box { - OnboardingActionBlock( - firstActionContent = { - SecondaryButton( - modifier = Modifier - .fillMaxWidth(), - text = stringResourceSafe(id = R.string.onboarding_seed_intro_button_generate), - enabled = state.buttonGenerateSeedPhrase.enabled, - showProgress = state.buttonGenerateSeedPhrase.showProgress, - onClick = state.buttonGenerateSeedPhrase.onClick, - ) - }, - secondActionContent = { - SecondaryButton( - modifier = Modifier - .fillMaxWidth(), - text = stringResourceSafe(id = R.string.onboarding_seed_intro_button_import), - enabled = state.buttonImportSeedPhrase.enabled, - showProgress = state.buttonImportSeedPhrase.showProgress, - onClick = state.buttonImportSeedPhrase.onClick, - ) - }, - ) - } - } -} - -@Composable -private fun EditIconBlock() { - Column( - modifier = Modifier - .fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - Image( - modifier = Modifier - .size(TangemTheme.dimens.size44), - painter = painterResource(id = R.drawable.ic_onboarding_text_edit_56), - contentDescription = null, - ) - SpacerH32() - Box( - modifier = Modifier - .background( - color = TangemTheme.colors.icon.warning.copy(alpha = 0.12f), - shape = RoundedCornerShape(TangemTheme.dimens.radius8), - ), - ) { - Text( - modifier = Modifier - .padding( - horizontal = TangemTheme.dimens.size12, - vertical = TangemTheme.dimens.size4, - ), - text = stringResourceSafe(id = R.string.onboarding_seed_phrase_intro_legacy), - color = TangemTheme.colors.text.warning, - style = TangemTheme.typography.body1, - ) - } - } -} - -@Composable -private fun ReadMoreBlock(state: AboutState) { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(top = TangemTheme.dimens.size16), - ) { - val shape = TangemTheme.shapes.roundedCornersLarge - Row( - modifier = Modifier - .align(Alignment.Center) - .clip(shape) - .border( - width = TangemTheme.dimens.size1, - color = TangemTheme.colors.stroke.primary, - shape = shape, - ) - .clickable(onClick = state.buttonReadMoreAboutSeedPhrase.onClick) - .padding( - horizontal = TangemTheme.dimens.size16, - vertical = TangemTheme.dimens.size8, - ), - ) { - Icon( - painter = painterResource(id = R.drawable.ic_arrow_top_right_24), - contentDescription = null, - tint = TangemTheme.colors.icon.primary1, - ) - SpacerW8() - Text( - text = stringResourceSafe(id = R.string.onboarding_seed_button_read_more), - color = TangemTheme.colors.text.primary1, - ) - } - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/CheckSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/CheckSeedPhraseScreen.kt deleted file mode 100644 index bf29010072..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/CheckSeedPhraseScreen.kt +++ /dev/null @@ -1,110 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusDirection -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardType -import com.tangem.core.ui.R -import com.tangem.core.ui.components.OutlineTextField -import com.tangem.core.ui.components.PrimaryButtonIconEnd -import com.tangem.core.ui.components.fields.contextmenu.DisableContextMenu -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.onboarding.presentation.wallet2.model.CheckSeedPhraseState -import com.tangem.feature.onboarding.presentation.wallet2.model.TextFieldState -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.Description -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingActionBlock -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingDescriptionBlock - -/** -[REDACTED_AUTHOR] - */ -@Suppress("ReusedModifierInstance") -@Composable -fun CheckSeedPhraseScreen(state: CheckSeedPhraseState, modifier: Modifier = Modifier) { - Column( - modifier = modifier - .fillMaxSize(), - ) { - LazyColumn( - modifier = modifier - .weight(1f) - .fillMaxWidth(), - ) { - item { - OnboardingDescriptionBlock( - modifier = Modifier - .weight(1f) - .padding(top = TangemTheme.dimens.size48) - .padding(horizontal = TangemTheme.dimens.size16), - ) { - Description( - titleRes = R.string.onboarding_seed_user_validation_title, - subTitleRes = R.string.onboarding_seed_user_validation_message, - ) - } - } - item { - CheckSeedPhraseBlock( - modifier = Modifier - .imePadding() - .weight(1f) - .padding(top = TangemTheme.dimens.size20) - .padding(horizontal = TangemTheme.dimens.size16), - state = state, - ) - } - } - OnboardingActionBlock( - firstActionContent = { - PrimaryButtonIconEnd( - modifier = Modifier - .fillMaxWidth(), - text = stringResourceSafe(id = R.string.onboarding_create_wallet_button_create_wallet), - iconResId = R.drawable.ic_tangem_24, - enabled = state.buttonCreateWallet.enabled, - showProgress = state.buttonCreateWallet.showProgress, - onClick = state.buttonCreateWallet.onClick, - ) - }, - ) - } -} - -@Composable -private fun CheckSeedPhraseBlock(state: CheckSeedPhraseState, modifier: Modifier = Modifier) { - Column(modifier) { - CheckSeedPhraseTextField(state = state.tvSecondPhrase, imeAction = ImeAction.Next) - CheckSeedPhraseTextField(state = state.tvSeventhPhrase, imeAction = ImeAction.Next) - CheckSeedPhraseTextField(state = state.tvEleventhPhrase, imeAction = ImeAction.Done) - } -} - -@Composable -private fun CheckSeedPhraseTextField(state: TextFieldState, imeAction: ImeAction) { - val focusManager = LocalFocusManager.current - - DisableContextMenu { - OutlineTextField( - value = state.textFieldValue, - onValueChange = state.onTextFieldValueChanged, - label = state.label, - isError = state.isError, - keyboardOptions = KeyboardOptions( - autoCorrectEnabled = false, - keyboardType = KeyboardType.Password, - imeAction = imeAction, - ), - keyboardActions = KeyboardActions( - onDone = { focusManager.clearFocus() }, - onNext = { focusManager.moveFocus(focusDirection = FocusDirection.Down) }, - ), - ) - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt deleted file mode 100644 index 7c03fef7bc..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt +++ /dev/null @@ -1,268 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui - -import android.content.res.Configuration -import androidx.compose.animation.* -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.IntOffset -import com.tangem.core.ui.components.* -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.feature.onboarding.R -import com.tangem.feature.onboarding.presentation.wallet2.model.ButtonState -import com.tangem.feature.onboarding.presentation.wallet2.model.ImportSeedPhraseState -import com.tangem.feature.onboarding.presentation.wallet2.model.TextFieldState -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.DescriptionSubTitleText -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingActionBlock -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingDescriptionBlock -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.InvalidWordsColorTransformation -import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseErrorConverter -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun ImportSeedPhraseScreen(state: ImportSeedPhraseState, modifier: Modifier = Modifier) { - val keyboard by keyboardAsState() - Box( - modifier = modifier.fillMaxSize(), - ) { - Column { - OnboardingDescriptionBlock( - modifier = Modifier.padding(top = TangemTheme.dimens.size16), - ) { - DescriptionSubTitleText(text = stringResourceSafe(id = R.string.onboarding_seed_import_message)) - } - PhraseBlock( - modifier = Modifier - .padding(top = TangemTheme.dimens.size62) - .padding(horizontal = TangemTheme.dimens.size16), - state = state, - ) - - PassphraseBlock( - modifier = Modifier.padding(horizontal = TangemTheme.dimens.size16), - passphraseField = state.fieldPassphrase, - onPassphraseInfoClick = state.onPassphraseInfoClick, - ) - - OnboardingActionBlock( - modifier = Modifier.padding(top = TangemTheme.dimens.size16), - firstActionContent = { - PrimaryButtonIconEnd( - modifier = Modifier - .fillMaxWidth(), - text = stringResourceSafe(id = R.string.common_import), - iconResId = R.drawable.ic_tangem_24, - enabled = state.buttonCreateWallet.enabled, - showProgress = state.buttonCreateWallet.showProgress, - onClick = state.buttonCreateWallet.onClick, - ) - }, - ) - } - - if (keyboard is Keyboard.Opened) { - SuggestionsBlock( - modifier = Modifier - .align(Alignment.BottomCenter) - .imePadding(), - suggestionsList = state.suggestionsList, - onClick = { index -> state.onSuggestedPhraseClick(index) }, - ) - } - - if (state.bottomSheetConfig != null) { - PassphraseInfoBottomSheet(config = state.bottomSheetConfig) - } - } -} - -@Composable -private fun PassphraseBlock( - passphraseField: TextFieldState, - onPassphraseInfoClick: () -> Unit, - modifier: Modifier = Modifier, -) { - OutlineTextFieldWithIcon( - modifier = modifier.fillMaxWidth(), - value = passphraseField.textFieldValue, - onValueChange = passphraseField.onTextFieldValueChanged, - iconResId = R.drawable.ic_information_24, - iconColor = TangemTheme.colors.icon.informative, - label = stringResourceSafe(id = R.string.common_passphrase), - placeholder = stringResourceSafe(id = R.string.send_optional_field), - onIconClick = onPassphraseInfoClick, - keyboardOptions = KeyboardOptions( - autoCorrectEnabled = false, - keyboardType = KeyboardType.Password, - ), - ) -} - -@Composable -private fun PhraseBlock(state: ImportSeedPhraseState, modifier: Modifier = Modifier) { - // TODO: replace by TextReference - val errorConverter = remember { SeedPhraseErrorConverter() } - - Column( - modifier = modifier.fillMaxWidth(), - ) { - OutlinedTextField( - modifier = Modifier - .fillMaxWidth() - .height(TangemTheme.dimens.size142), - value = state.fieldSeedPhrase.textFieldValue, - onValueChange = state.fieldSeedPhrase.onTextFieldValueChanged, - textStyle = TangemTheme.typography.body1, - singleLine = false, - visualTransformation = InvalidWordsColorTransformation( - wordsToBrush = state.invalidWords, - style = SpanStyle(color = TangemTheme.colors.text.warning), - ), - colors = TangemTextFieldsDefault.defaultTextFieldColors, - keyboardOptions = KeyboardOptions( - autoCorrectEnabled = false, - keyboardType = KeyboardType.Password, - ), - ) - - Box( - modifier = Modifier - .fillMaxWidth() - .height(TangemTheme.dimens.size32), - ) { - val message = errorConverter.convert(LocalContext.current to state.error) - if (message != null) { - Text( - modifier = Modifier.fillMaxSize(), - text = message, - style = TangemTheme.typography.caption2.copy( - color = TangemTheme.colors.text.warning, - ), - ) - } - } - } -} - -@Suppress("ReusedModifierInstance") -@Composable -private fun SuggestionsBlock( - suggestionsList: ImmutableList, - onClick: (Int) -> Unit, - modifier: Modifier = Modifier, -) { - AnimatedVisibility( - modifier = modifier, - enter = fadeIn() + slideIn(initialOffset = { IntOffset(x = 200, y = 0) }), - exit = slideOut(targetOffset = { IntOffset(x = -200, y = 0) }) + fadeOut(), - visible = suggestionsList.isNotEmpty(), - ) { - LazyRow( - contentPadding = PaddingValues(horizontal = TangemTheme.dimens.size16), - ) { - items(suggestionsList.size) { index -> - SuggestionButton( - modifier = Modifier.rowPadding( - index = index, - rowSize = suggestionsList.size, - outSide = TangemTheme.dimens.size0, - inSide = TangemTheme.dimens.size4, - ), - text = suggestionsList[index], - onClick = { onClick(index) }, - ) - } - } - } -} - -@Composable -private fun SuggestionButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier) { - Box(modifier = modifier.clickable(onClick = onClick)) { - Notifier( - text = text, - backgroundColor = TangemTheme.colors.icon.primary1, - textColor = TangemTheme.colors.text.primary2, - ) - } -} - -private fun Modifier.rowPadding(index: Int, rowSize: Int, outSide: Dp, inSide: Dp): Modifier = when (index) { - 0 -> this.padding(start = outSide, end = inSide) - rowSize - 1 -> this.padding(start = inSide, end = outSide) - else -> this.padding(horizontal = inSide) -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun SuggestionsBlockPreview( - @PreviewParameter(SuggestionsPreviewParamsProvider::class) suggestions: ImmutableList, -) { - TangemThemePreview { - SuggestionsBlock( - suggestionsList = suggestions, - onClick = {}, - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun ImportSeedPhraseScreenPreview( - @PreviewParameter(SuggestionsPreviewParamsProvider::class) suggestions: ImmutableList, -) { - TangemThemePreview { - Box(modifier = Modifier.background(TangemTheme.colors.background.primary)) { - ImportSeedPhraseScreen( - ImportSeedPhraseState( - fieldSeedPhrase = TextFieldState(onTextFieldValueChanged = {}), - fieldPassphrase = TextFieldState(onTextFieldValueChanged = {}), - onSuggestedPhraseClick = {}, - onPassphraseInfoClick = {}, - buttonCreateWallet = ButtonState( - enabled = true, - isClickable = true, - showProgress = false, - onClick = {}, - ), - suggestionsList = suggestions, - ), - ) - } - } -} - -private class SuggestionsPreviewParamsProvider : CollectionPreviewParameterProvider>( - collection = listOf( - persistentListOf( - "one", - "each", - "explorer", - "unknown", - ), - ), -) \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/IntroScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/IntroScreen.kt deleted file mode 100644 index 5691a1b124..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/IntroScreen.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.* -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import coil.compose.SubcomposeAsyncImage -import coil.request.ImageRequest -import com.tangem.core.ui.components.PrimaryButtonIconEnd -import com.tangem.core.ui.components.SecondaryButton -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.onboarding.R -import com.tangem.feature.onboarding.presentation.wallet2.model.IntroState -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.Description -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingActionBlock -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingDescriptionBlock - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun IntroScreen(state: IntroState, modifier: Modifier = Modifier) { - Column( - modifier = modifier.fillMaxSize(), - ) { - Box( - modifier = Modifier.weight(weight = 1.5f), - ) { - CardImageBlock(state.cardImageUrl) - } - Box( - modifier = Modifier.weight(weight = 1f), - ) { - OnboardingDescriptionBlock { - Description( - titleRes = R.string.onboarding_create_wallet_options_title, - subTitleRes = R.string.onboarding_create_wallet_options_message, - ) - } - } - Box { - OnboardingActionBlock( - firstActionContent = { - PrimaryButtonIconEnd( - modifier = Modifier - .fillMaxWidth(), - text = stringResourceSafe(id = R.string.onboarding_create_wallet_button_create_wallet), - iconResId = R.drawable.ic_tangem_24, - enabled = state.buttonCreateWallet.enabled, - showProgress = state.buttonCreateWallet.showProgress, - onClick = state.buttonCreateWallet.onClick, - ) - }, - secondActionContent = { - SecondaryButton( - modifier = Modifier - .fillMaxWidth(), - text = stringResourceSafe(id = R.string.onboarding_create_wallet_options_button_options), - enabled = state.buttonOtherOptions.enabled, - showProgress = state.buttonOtherOptions.showProgress, - onClick = state.buttonOtherOptions.onClick, - ) - }, - ) - } - } -} - -@Composable -private fun CardImageBlock(cardImageUrl: String? = null) { - Box(modifier = Modifier.fillMaxSize()) { - val cardImageModifier = Modifier - .fillMaxSize() - .align(Alignment.Center) - - SubcomposeAsyncImage( - modifier = cardImageModifier.padding(horizontal = TangemTheme.dimens.size34), - model = ImageRequest.Builder(LocalContext.current) - .data(cardImageUrl) - .crossfade(true) - .build(), - loading = { CardPlaceHolder(cardImageModifier) }, - error = { CardPlaceHolder(cardImageModifier) }, - contentDescription = null, - ) - } -} - -@Composable -private fun CardPlaceHolder(modifier: Modifier = Modifier) { - Image( - modifier = modifier, - painter = painterResource(id = R.drawable.card_placeholder_black), - contentScale = ContentScale.Fit, - contentDescription = null, - ) -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt deleted file mode 100644 index a2912a2666..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt +++ /dev/null @@ -1,90 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.PrimaryButton -import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.feature.onboarding.R -import com.tangem.feature.onboarding.presentation.wallet2.model.ShowPassphraseInfoBottomSheetContent - -@Composable -fun PassphraseInfoBottomSheet(config: TangemBottomSheetConfig) { - TangemBottomSheet( - config = config, - containerColor = TangemTheme.colors.background.primary, - ) { content: ShowPassphraseInfoBottomSheetContent -> - PassphraseInfoBottomSheetContent(content) - } -} - -@Composable -fun PassphraseInfoBottomSheetContent(content: ShowPassphraseInfoBottomSheetContent) { - Column( - modifier = Modifier - .background(color = TangemTheme.colors.background.primary) - .fillMaxWidth(), - ) { - Icon( - modifier = Modifier - .align(Alignment.CenterHorizontally) - .padding(top = TangemTheme.dimens.size40) - .size(TangemTheme.dimens.size48), - painter = painterResource(id = R.drawable.ic_information_24), - tint = TangemTheme.colors.icon.accent, - contentDescription = null, - ) - - Text( - text = stringResourceSafe(id = R.string.common_passphrase), - modifier = Modifier - .padding(top = TangemTheme.dimens.size40) - .align(Alignment.CenterHorizontally), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.h2, - ) - - Text( - text = stringResourceSafe(id = R.string.onboarding_bottom_sheet_passphrase_description), - modifier = Modifier - .padding(top = TangemTheme.dimens.size16) - .padding(horizontal = TangemTheme.dimens.size24) - .align(Alignment.CenterHorizontally), - color = TangemTheme.colors.text.secondary, - style = TangemTheme.typography.body2, - textAlign = TextAlign.Center, - ) - - PrimaryButton( - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.size16) - .padding(top = TangemTheme.dimens.size40) - .padding(bottom = TangemTheme.dimens.size32) - .fillMaxWidth(), - text = stringResourceSafe(id = R.string.common_ok), - onClick = content.onOkClick, - ) - } -} - -@Preview -@Composable -private fun PassphraseInfoBottomSheetContentPreview() { - TangemThemePreview { - PassphraseInfoBottomSheetContent(ShowPassphraseInfoBottomSheetContent { }) - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt deleted file mode 100644 index 2f7f864d6e..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt +++ /dev/null @@ -1,196 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.PrimaryButton -import com.tangem.core.ui.components.SpacerH16 -import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons -import com.tangem.core.ui.extensions.pluralStringResourceSafe -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.feature.onboarding.R -import com.tangem.feature.onboarding.presentation.wallet2.model.* -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.DescriptionSubTitleText -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.DescriptionTitleText -import com.tangem.feature.onboarding.presentation.wallet2.ui.components.OnboardingActionBlock -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toPersistentList - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun YourSeedPhraseScreen(state: YourSeedPhraseState, modifier: Modifier = Modifier) { - Box( - modifier = modifier.fillMaxSize(), - ) { - Column( - modifier = Modifier - .padding(bottom = TangemTheme.dimens.spacing92) - .verticalScroll(rememberScrollState()) - .fillMaxSize(), - ) { - SegmentSeedBlock( - modifier = Modifier.padding(top = TangemTheme.dimens.spacing20), - state = state.segmentSeedState, - ) - - TitleBlock(state.segmentSeedState) - - SeedPhraseGridBlock( - modifier = Modifier - .padding(top = TangemTheme.dimens.spacing20) - .padding(horizontal = TangemTheme.dimens.size16), - mnemonicGridItems = state.mnemonicGridItems, - ) - } - OnboardingActionBlock( - modifier = Modifier.align(Alignment.BottomCenter), - firstActionContent = { - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - text = stringResourceSafe(id = R.string.common_continue), - onClick = state.buttonContinue.onClick, - ) - }, - ) - } -} - -@Composable -private fun TitleBlock(state: SegmentSeedState) { - Box( - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.size36) - .padding(top = TangemTheme.dimens.spacing20) - .fillMaxWidth(), - ) { - Column { - DescriptionTitleText(text = stringResourceSafe(id = R.string.onboarding_seed_generate_title)) - SpacerH16() - DescriptionSubTitleText( - text = pluralStringResourceSafe( - id = R.plurals.onboarding_seed_generate_message_words_count, - count = state.selectedSeedType.count, - state.selectedSeedType.count, - ), - ) - } - } -} - -@Composable -private fun SegmentSeedBlock(state: SegmentSeedState, modifier: Modifier = Modifier) { - SegmentedButtons( - modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing76), - config = state.seedSegments, - initialSelectedItem = state.selectedSeedType, - onClick = { - state.onSelectType(it) - }, - ) { - Text( - text = pluralStringResourceSafe( - id = R.plurals.onboarding_seed_generate_words_count, - count = it.count, - it.count, - ), - modifier = Modifier - .padding(vertical = TangemTheme.dimens.spacing10) - .fillMaxWidth(), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.Center, - ) - } -} - -@Composable -private fun SeedPhraseGridBlock(mnemonicGridItems: ImmutableList, modifier: Modifier = Modifier) { - VerticalGrid( - modifier = modifier, - items = mnemonicGridItems, - columns = 2, - ) { item -> - Row( - modifier = Modifier.padding(all = TangemTheme.dimens.size8), - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - modifier = Modifier.width(TangemTheme.dimens.size40), - text = "${item.index}.", - style = TangemTheme.typography.body2, - color = TangemTheme.colors.text.secondary, - ) - Text( - text = item.mnemonic, - style = TangemTheme.typography.button, - color = TangemTheme.colors.text.primary1, - ) - } - } -} - -@Composable -private inline fun VerticalGrid( - items: ImmutableList, - columns: Int, - modifier: Modifier = Modifier, - crossinline content: @Composable (T) -> Unit, -) { - val columnLength = items.size / columns - Row( - modifier = modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly, - ) { - for (index in 0 until columns) { - Column { - for (i in 0 until columnLength) { - val item = items[index * columnLength + i] - content(item) - } - } - } - } -} - -@Preview(widthDp = 360, showBackground = true) -@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun YourSeedPhraseScreenPreview_Light() { - TangemThemePreview { - YourSeedPhraseScreen( - state = YourSeedPhraseState( - segmentSeedState = SegmentSeedState( - seedSegments = persistentListOf( - SegmentSeedType.SEED_12, - SegmentSeedType.SEED_24, - ), - selectedSeedType = SegmentSeedType.SEED_24, - onSelectType = {}, - ), - mnemonicGridItems = (1..24).map { MnemonicGridItem(it, it.toString()) }.toPersistentList(), - buttonContinue = ButtonState( - enabled = true, - isClickable = true, - showProgress = false, - onClick = {}, - ), - ), - modifier = Modifier - .fillMaxSize() - .background(color = TangemTheme.colors.background.primary), - ) - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingActionBlock.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingActionBlock.kt deleted file mode 100644 index 986bcac496..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingActionBlock.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui.components - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import com.tangem.core.ui.components.SpacerH12 -import com.tangem.core.ui.res.TangemTheme - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun OnboardingActionBlock( - modifier: Modifier = Modifier, - firstActionContent: @Composable (() -> Unit)? = null, - secondActionContent: @Composable (() -> Unit)? = null, -) { - if (firstActionContent == null && secondActionContent == null) return - - Box( - modifier = modifier - .padding(horizontal = TangemTheme.dimens.size16) - .padding( - top = TangemTheme.dimens.size8, - bottom = TangemTheme.dimens.size32, - ), - ) { - Column( - modifier = Modifier.align(Alignment.BottomCenter), - ) { - firstActionContent?.invoke() - if (firstActionContent != null && secondActionContent != null) SpacerH12() - secondActionContent?.invoke() - } - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt deleted file mode 100644 index 52806b14c3..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui.components - -import androidx.annotation.StringRes -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.sp -import com.tangem.core.ui.components.SpacerH16 -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.TangemTheme - -/** - * UI component witch provides single and carousel description for the onboarding process - */ -@Composable -fun OnboardingDescriptionBlock(modifier: Modifier = Modifier, content: @Composable () -> Unit) { - Box( - modifier = modifier - .fillMaxWidth() - .padding(horizontal = TangemTheme.dimens.size36), - ) { - content() - } -} - -@Composable -fun Description(@StringRes titleRes: Int, @StringRes subTitleRes: Int) { - Column { - DescriptionTitleText(text = stringResourceSafe(id = titleRes)) - SpacerH16() - DescriptionSubTitleText(text = stringResourceSafe(id = subTitleRes)) - } -} - -@Composable -fun DescriptionTitleText(text: String) { - Text( - text = text, - style = TangemTheme.typography.h2, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.Center, - modifier = Modifier.fillMaxWidth(), - ) -} - -@Composable -fun DescriptionSubTitleText(text: String) { - // the text style made similar to TextViewOnboarding.Body - Text( - text = text, - style = TangemTheme.typography.body1.copy( - lineHeight = 20.sp, - letterSpacing = 0.03.sp, - ), - color = TangemTheme.colors.text.secondary, - textAlign = TextAlign.Center, - modifier = Modifier.fillMaxWidth(), - ) -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/CheckSeedPhraseStateBuilder.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/CheckSeedPhraseStateBuilder.kt deleted file mode 100644 index aad9659b9d..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/CheckSeedPhraseStateBuilder.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui.stateBuiders - -import androidx.compose.ui.text.input.TextFieldValue -import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState -import com.tangem.feature.onboarding.presentation.wallet2.model.SeedPhraseField - -/** -[REDACTED_AUTHOR] - */ -class CheckSeedPhraseStateBuilder { - - fun updateTextField( - uiState: OnboardingSeedPhraseState, - field: SeedPhraseField, - textFieldValue: TextFieldValue, - ): OnboardingSeedPhraseState = when (field) { - SeedPhraseField.Second -> uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - tvSecondPhrase = uiState.checkSeedPhraseState.tvSecondPhrase.copy( - textFieldValue = textFieldValue, - ), - ), - ) - SeedPhraseField.Seventh -> uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - tvSeventhPhrase = uiState.checkSeedPhraseState.tvSeventhPhrase.copy( - textFieldValue = textFieldValue, - ), - ), - ) - SeedPhraseField.Eleventh -> uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - tvEleventhPhrase = uiState.checkSeedPhraseState.tvEleventhPhrase.copy( - textFieldValue = textFieldValue, - ), - ), - ) - } - - fun updateTextFieldError( - uiState: OnboardingSeedPhraseState, - field: SeedPhraseField, - hasError: Boolean, - ): OnboardingSeedPhraseState = when (field) { - SeedPhraseField.Second -> uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - tvSecondPhrase = uiState.checkSeedPhraseState.tvSecondPhrase.copy( - isError = hasError, - ), - ), - ) - SeedPhraseField.Seventh -> uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - tvSeventhPhrase = uiState.checkSeedPhraseState.tvSeventhPhrase.copy( - isError = hasError, - ), - ), - ) - SeedPhraseField.Eleventh -> uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - tvEleventhPhrase = uiState.checkSeedPhraseState.tvEleventhPhrase.copy( - isError = hasError, - ), - ), - ) - } - - fun updateCreateWalletButton(uiState: OnboardingSeedPhraseState, enabled: Boolean): OnboardingSeedPhraseState { - return uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - buttonCreateWallet = uiState.checkSeedPhraseState.buttonCreateWallet.copy( - enabled = enabled, - ), - ), - ) - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/ImportSeedPhraseStateBuilder.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/ImportSeedPhraseStateBuilder.kt deleted file mode 100644 index 5562ff3af5..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/ImportSeedPhraseStateBuilder.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui.stateBuiders - -import androidx.compose.ui.text.TextRange -import androidx.compose.ui.text.input.TextFieldValue -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.feature.onboarding.domain.InsertSuggestionResult -import com.tangem.feature.onboarding.domain.SeedPhraseError -import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState -import com.tangem.feature.onboarding.presentation.wallet2.model.ShowPassphraseInfoBottomSheetContent -import kotlinx.collections.immutable.ImmutableList - -/** -[REDACTED_AUTHOR] - */ -class ImportSeedPhraseStateBuilder { - - fun updateSeedPhraseTextField( - uiState: OnboardingSeedPhraseState, - textFieldValue: TextFieldValue, - ): OnboardingSeedPhraseState = uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - fieldSeedPhrase = uiState.importSeedPhraseState.fieldSeedPhrase.copy( - textFieldValue = textFieldValue, - ), - ), - ) - - fun updatePassPhraseTextField( - uiState: OnboardingSeedPhraseState, - textFieldValue: TextFieldValue, - ): OnboardingSeedPhraseState = uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - fieldPassphrase = uiState.importSeedPhraseState.fieldPassphrase.copy( - textFieldValue = textFieldValue, - ), - ), - ) - - fun updateCreateWalletButton(uiState: OnboardingSeedPhraseState, enabled: Boolean): OnboardingSeedPhraseState { - return uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - buttonCreateWallet = uiState.importSeedPhraseState.buttonCreateWallet.copy( - enabled = enabled, - ), - ), - ) - } - - fun updateInvalidWords(uiState: OnboardingSeedPhraseState, invalidWords: Set): OnboardingSeedPhraseState = - uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - invalidWords = invalidWords, - ), - ) - - fun updateSuggestions( - uiState: OnboardingSeedPhraseState, - suggestions: ImmutableList, - ): OnboardingSeedPhraseState = uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - suggestionsList = suggestions, - ), - ) - - fun showPassphraseInfoBottomSheet( - uiState: OnboardingSeedPhraseState, - onDismiss: () -> Unit, - ): OnboardingSeedPhraseState { - return uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - bottomSheetConfig = TangemBottomSheetConfig( - isShown = true, - onDismissRequest = onDismiss, - content = ShowPassphraseInfoBottomSheetContent(onDismiss), - ), - ), - ) - } - - fun dismissPassphraseBottomSheet(uiState: OnboardingSeedPhraseState): OnboardingSeedPhraseState { - return uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - bottomSheetConfig = uiState.importSeedPhraseState.bottomSheetConfig?.copy( - isShown = false, - ), - ), - ) - } - - fun insertSuggestionWord( - uiState: OnboardingSeedPhraseState, - insertResult: InsertSuggestionResult, - ): OnboardingSeedPhraseState { - val newTextFieldValue = uiState.importSeedPhraseState.fieldSeedPhrase.textFieldValue.copy( - text = insertResult.text, - selection = TextRange(insertResult.cursorPosition, insertResult.cursorPosition), - ) - return updateSeedPhraseTextField(uiState, newTextFieldValue) - } - - fun updateError(uiState: OnboardingSeedPhraseState, error: SeedPhraseError?): OnboardingSeedPhraseState { - return uiState.copy( - importSeedPhraseState = uiState.importSeedPhraseState.copy( - error = error, - ), - ) - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/StateBuilder.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/StateBuilder.kt deleted file mode 100644 index 3a27500c46..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/stateBuiders/StateBuilder.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.ui.stateBuiders - -import com.tangem.feature.onboarding.presentation.wallet2.model.* -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.persistentListOf - -/** -[REDACTED_AUTHOR] - */ -class StateBuilder( - private val uiActions: UiActions, -) { - - val checkSeedPhrase: CheckSeedPhraseStateBuilder = CheckSeedPhraseStateBuilder() - val importSeedPhrase: ImportSeedPhraseStateBuilder = ImportSeedPhraseStateBuilder() - - fun init(selectedSeedType: SegmentSeedType): OnboardingSeedPhraseState = OnboardingSeedPhraseState( - introState = getInitialIntroState(), - aboutState = getInitialAboutState(), - yourSeedPhraseState = getInitialYourSeedPhraseState(selectedSeedType), - checkSeedPhraseState = getInitialCheckSeedPhraseState(), - importSeedPhraseState = getInitialImportSeedPhraseState(), - menuButtonChat = ButtonState( - onClick = uiActions.menuChatClick, - ), - onBackClick = uiActions.menuNavigateBackClick, - ) - - private fun getInitialImportSeedPhraseState(): ImportSeedPhraseState { - return ImportSeedPhraseState( - fieldSeedPhrase = TextFieldState( - onTextFieldValueChanged = uiActions.importSeedPhraseActions.phraseTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.importSeedPhraseActions.phraseTextFieldAction.onFocusChanged, - ), - fieldPassphrase = TextFieldState( - onTextFieldValueChanged = uiActions.importSeedPhraseActions.passTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.importSeedPhraseActions.passTextFieldAction.onFocusChanged, - ), - onSuggestedPhraseClick = uiActions.importSeedPhraseActions.suggestedPhraseClick, - onPassphraseInfoClick = uiActions.importSeedPhraseActions.onPassphraseInfoClick, - buttonCreateWallet = ButtonState( - enabled = false, - onClick = uiActions.importSeedPhraseActions.buttonCreateWalletClick, - ), - ) - } - - private fun getInitialCheckSeedPhraseState(): CheckSeedPhraseState { - return CheckSeedPhraseState( - tvSecondPhrase = TextFieldState( - label = "2", - isFocused = true, - onTextFieldValueChanged = uiActions.checkSeedPhraseActions.secondTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.checkSeedPhraseActions.secondTextFieldAction.onFocusChanged, - ), - tvSeventhPhrase = TextFieldState( - label = "7", - isFocused = false, - onTextFieldValueChanged = uiActions.checkSeedPhraseActions.seventhTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.checkSeedPhraseActions.seventhTextFieldAction.onFocusChanged, - ), - tvEleventhPhrase = TextFieldState( - label = "11", - isFocused = false, - onTextFieldValueChanged = uiActions.checkSeedPhraseActions.eleventhTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.checkSeedPhraseActions.eleventhTextFieldAction.onFocusChanged, - ), - buttonCreateWallet = ButtonState( - enabled = false, - onClick = uiActions.checkSeedPhraseActions.buttonCreateWalletClick, - ), - ) - } - - private fun getInitialYourSeedPhraseState(selectedSeedType: SegmentSeedType): YourSeedPhraseState { - return YourSeedPhraseState( - segmentSeedState = SegmentSeedState( - seedSegments = persistentListOf( - SegmentSeedType.SEED_12, - SegmentSeedType.SEED_24, - ), - selectedSeedType = selectedSeedType, - onSelectType = uiActions.yourSeedPhraseActions.onSelectType, - ), - buttonContinue = ButtonState( - onClick = uiActions.yourSeedPhraseActions.buttonContinueClick, - ), - ) - } - - private fun getInitialAboutState(): AboutState { - return AboutState( - buttonReadMoreAboutSeedPhrase = ButtonState( - onClick = uiActions.aboutActions.buttonReadMoreAboutSeedPhraseClick, - ), - buttonGenerateSeedPhrase = ButtonState( - onClick = uiActions.aboutActions.buttonGenerateSeedPhraseClick, - ), - buttonImportSeedPhrase = ButtonState( - onClick = uiActions.aboutActions.buttonImportSeedPhraseClick, - ), - ) - } - - private fun getInitialIntroState(): IntroState { - return IntroState( - buttonCreateWallet = ButtonState( - onClick = uiActions.introActions.buttonCreateWalletClick, - ), - buttonOtherOptions = ButtonState( - onClick = uiActions.introActions.buttonOtherOptionsClick, - ), - ) - } - - fun setCardArtwork(uiState: OnboardingSeedPhraseState, cardArtwork: String): OnboardingSeedPhraseState = - uiState.copy( - introState = uiState.introState.copy( - cardImageUrl = cardArtwork, - ), - ) - - fun generateMnemonicComponents(uiState: OnboardingSeedPhraseState): OnboardingSeedPhraseState { - return uiState.copy( - aboutState = uiState.aboutState.copy( - buttonGenerateSeedPhrase = uiState.aboutState.buttonGenerateSeedPhrase.copy( - showProgress = true, - ), - buttonImportSeedPhrase = uiState.aboutState.buttonImportSeedPhrase.copy( - enabled = false, - ), - ), - ) - } - - fun mnemonicGenerated( - uiState: OnboardingSeedPhraseState, - mnemonicGridItems: PersistentList, - ): OnboardingSeedPhraseState { - return updateMnemonicComponents(uiState, mnemonicGridItems) - .copy( - aboutState = uiState.aboutState.copy( - buttonGenerateSeedPhrase = uiState.aboutState.buttonGenerateSeedPhrase.copy( - showProgress = false, - ), - buttonImportSeedPhrase = uiState.aboutState.buttonImportSeedPhrase.copy( - enabled = true, - ), - ), - ) - } - - fun selectSeedType( - uiState: OnboardingSeedPhraseState, - mnemonicGridItems: PersistentList, - selectedSeedType: SegmentSeedType, - ): OnboardingSeedPhraseState = uiState.copy( - yourSeedPhraseState = uiState.yourSeedPhraseState.copy( - mnemonicGridItems = mnemonicGridItems, - segmentSeedState = uiState.yourSeedPhraseState.segmentSeedState.copy( - selectedSeedType = selectedSeedType, - ), - ), - ) - - fun clearCheckSeedPhraseState(uiState: OnboardingSeedPhraseState): OnboardingSeedPhraseState = uiState.copy( - checkSeedPhraseState = uiState.checkSeedPhraseState.copy( - tvSecondPhrase = TextFieldState( - label = "2", - isFocused = true, - onTextFieldValueChanged = uiActions.checkSeedPhraseActions.secondTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.checkSeedPhraseActions.secondTextFieldAction.onFocusChanged, - ), - tvSeventhPhrase = TextFieldState( - label = "7", - isFocused = false, - onTextFieldValueChanged = uiActions.checkSeedPhraseActions.seventhTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.checkSeedPhraseActions.seventhTextFieldAction.onFocusChanged, - ), - tvEleventhPhrase = TextFieldState( - label = "11", - isFocused = false, - onTextFieldValueChanged = uiActions.checkSeedPhraseActions.eleventhTextFieldAction.onTextFieldChanged, - onFocusChanged = uiActions.checkSeedPhraseActions.eleventhTextFieldAction.onFocusChanged, - ), - ), - ) - - private fun updateMnemonicComponents( - uiState: OnboardingSeedPhraseState, - mnemonicGridItems: PersistentList, - ): OnboardingSeedPhraseState = uiState.copy( - yourSeedPhraseState = uiState.yourSeedPhraseState.copy( - mnemonicGridItems = mnemonicGridItems, - ), - ) -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/InvalidWordsColorTransformation.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/InvalidWordsColorTransformation.kt deleted file mode 100644 index 7d6f3a4685..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/InvalidWordsColorTransformation.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.viewmodel - -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.input.OffsetMapping -import androidx.compose.ui.text.input.TransformedText -import androidx.compose.ui.text.input.VisualTransformation -import com.tangem.utils.extensions.isSingleItem - -/** -[REDACTED_AUTHOR] - */ -class InvalidWordsColorTransformation( - private val wordsToBrush: Set, - private val style: SpanStyle, -) : VisualTransformation { - - override fun filter(text: AnnotatedString): TransformedText { - val plainText = text.text - if (wordsToBrush.isSingleItem() && wordsToBrush.first() == plainText) { - return plainText.annotate().toTransformedText() - } - - val wordList = makeSeparatedWordlist(plainText) - val annotatedString = makeAnnotatedString(wordList) - - return annotatedString.toTransformedText() - } - - private fun makeSeparatedWordlist(plainText: String): List { - val plainTextCharArray = plainText.toCharArray() - val wordlist = mutableListOf() - var wordBuilder = StringBuilder() - - for (index in plainTextCharArray.indices) { - val char = plainTextCharArray[index] - if (char.isWhitespace()) { - if (wordBuilder.isEmpty()) { - wordlist.add(WORD_SEPARATOR) - } else { - wordlist.add(wordBuilder.toString()) - wordBuilder = StringBuilder() - wordlist.add(WORD_SEPARATOR) - } - } else { - if (index == plainTextCharArray.lastIndex) { - wordBuilder.append(char) - wordlist.add(wordBuilder.toString()) - wordBuilder = StringBuilder() - } else { - wordBuilder.append(char) - } - } - } - return wordlist.toList() - } - - private fun makeAnnotatedString(wordList: List): AnnotatedString = buildAnnotatedString { - wordList.forEach { - if (it == WORD_SEPARATOR) { - append(WHITE_SPACE) - } else if (wordsToBrush.contains(it)) { - append(it.annotate()) - } else { - append(it) - } - } - } - - private fun String.annotate(): AnnotatedString = AnnotatedString(this, style) - - private fun AnnotatedString.toTransformedText(): TransformedText = TransformedText(this, OffsetMapping.Identity) - - companion object { - private const val WHITE_SPACE = " " - private const val WORD_SEPARATOR = "_$@-*" - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseErrorConverter.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseErrorConverter.kt deleted file mode 100644 index 9a44793b6f..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseErrorConverter.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.viewmodel - -import android.content.Context -import com.tangem.common.module.ModuleMessageConverter -import com.tangem.feature.onboarding.R -import com.tangem.feature.onboarding.domain.SeedPhraseError - -/** -[REDACTED_AUTHOR] - */ -class SeedPhraseErrorConverter : ModuleMessageConverter, String?> { - - override fun convert(source: Pair): String? { - val (context, message) = source - - val convertedMessage = when (message) { - SeedPhraseError.InvalidChecksum -> { - context.getString(R.string.onboarding_seed_mnemonic_invalid_checksum) - } - is SeedPhraseError.InvalidWords -> { - context.getString(R.string.onboarding_seed_mnemonic_wrong_words) - } - else -> null - } - - return convertedMessage - } -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseMediator.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseMediator.kt deleted file mode 100644 index 5848187991..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseMediator.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.viewmodel - -import com.tangem.common.CompletionResult -import com.tangem.feature.onboarding.data.model.CreateWalletResponse -import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource - -/** -[REDACTED_AUTHOR] - */ -interface SeedPhraseMediator { - fun createWallet(callback: (CompletionResult) -> Unit) - fun importWallet( - mnemonicComponents: List, - passphrase: String?, - seedPhraseSource: SeedPhraseSource, - callback: (CompletionResult) -> Unit, - ) - - fun onWalletCreated(result: CompletionResult) - - fun allowScreenshots(allow: Boolean) -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseRouter.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseRouter.kt deleted file mode 100644 index 4fd0dc3ee4..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseRouter.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.viewmodel - -import android.net.Uri -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow - -/** -[REDACTED_AUTHOR] - */ -class SeedPhraseRouter( - private val onBack: () -> Unit, - private val onOpenChat: () -> Unit, - private val onOpenUriClick: (Uri) -> Unit, -) { - - private val _currentScreen = MutableStateFlow(SeedPhraseScreen.Intro) - - val currentScreen: StateFlow - get() = _currentScreen - - fun navigateBack() { - _currentScreen.value = when (_currentScreen.value) { - SeedPhraseScreen.CheckSeedPhrase -> SeedPhraseScreen.YourSeedPhrase - SeedPhraseScreen.AboutSeedPhrase -> SeedPhraseScreen.Intro - SeedPhraseScreen.ImportSeedPhrase, - SeedPhraseScreen.YourSeedPhrase, - -> SeedPhraseScreen.AboutSeedPhrase - SeedPhraseScreen.Intro -> { - onBack.invoke() - return - } - } - } - - fun openScreen(screen: SeedPhraseScreen) { - _currentScreen.value = screen - } - - fun openChat() { - onOpenChat.invoke() - } - - fun openUri(uri: Uri) { - onOpenUriClick.invoke(uri) - } -} - -enum class SeedPhraseScreen { - Intro, AboutSeedPhrase, YourSeedPhrase, CheckSeedPhrase, ImportSeedPhrase -} \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt deleted file mode 100644 index 8e7e49d5c7..0000000000 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt +++ /dev/null @@ -1,484 +0,0 @@ -package com.tangem.feature.onboarding.presentation.wallet2.viewmodel - -import android.net.Uri -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.compose.ui.text.input.TextFieldValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.tangem.common.CompletionResult -import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.data.common.locale.LocaleProvider -import com.tangem.feature.onboarding.data.model.CreateWalletResponse -import com.tangem.feature.onboarding.domain.SeedPhraseError -import com.tangem.feature.onboarding.domain.SeedPhraseInteractor -import com.tangem.feature.onboarding.domain.models.MnemonicType -import com.tangem.feature.onboarding.presentation.wallet2.analytics.CreateWalletEvents -import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseEvents -import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource -import com.tangem.feature.onboarding.presentation.wallet2.model.* -import com.tangem.feature.onboarding.presentation.wallet2.model.SegmentSeedType.Companion.fromMnemonicType -import com.tangem.feature.onboarding.presentation.wallet2.ui.stateBuiders.StateBuilder -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import com.tangem.utils.coroutines.Debouncer -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toPersistentList -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -/** -[REDACTED_AUTHOR] - */ -@Suppress("LargeClass") -@HiltViewModel -class SeedPhraseViewModel @Inject constructor( - private val interactor: SeedPhraseInteractor, - private val localeProvider: LocaleProvider, - private val dispatchers: CoroutineDispatcherProvider, - private val analyticsEventHandler: AnalyticsEventHandler, -) : ViewModel() { - - private var uiBuilder = StateBuilder(uiActions = createUiActions()) - - private var selectedMnemonicType = MnemonicType.Mnemonic12 - var uiState: OnboardingSeedPhraseState by mutableStateOf(uiBuilder.init(fromMnemonicType(selectedMnemonicType))) - private set - - private lateinit var router: SeedPhraseRouter - private lateinit var mediator: SeedPhraseMediator - - val currentScreen: StateFlow - get() = router.currentScreen - - val progress: Flow - get() = currentScreen.map { progressByScreen[it] ?: 0 } - - val maxProgress: Int by lazy { progressByScreen.maxOfOrNull { it.value } ?: 0 } - - var isFinished: Boolean = false - private set - - private val progressByScreen = mapOf( - SeedPhraseScreen.Intro to 1, - SeedPhraseScreen.AboutSeedPhrase to 2, - SeedPhraseScreen.YourSeedPhrase to 3, - SeedPhraseScreen.CheckSeedPhrase to 3, - SeedPhraseScreen.ImportSeedPhrase to 3, - ) - - private val textFieldsDebouncers = mutableMapOf() - - private var generatedMnemonicComponents: Map> = emptyMap() - private var importedMnemonicComponents: List? = null - private var importedPassphrase: String? = null - - override fun onCleared() { - textFieldsDebouncers.forEach { entry -> entry.value.release() } - textFieldsDebouncers.clear() - super.onCleared() - } - - fun setRouter(router: SeedPhraseRouter) { - this.router = router - subscribeToScreenChanges() - } - - private fun subscribeToScreenChanges() { - router.currentScreen.onEach { screen -> - when (screen) { - SeedPhraseScreen.Intro -> { - /* no-op */ - } - - SeedPhraseScreen.AboutSeedPhrase -> { - analyticsEventHandler.send(SeedPhraseEvents.IntroScreenOpened) - mediator.allowScreenshots(true) - } - - SeedPhraseScreen.YourSeedPhrase -> { - analyticsEventHandler.send(SeedPhraseEvents.GenerationScreenOpened) - mediator.allowScreenshots(false) - } - - SeedPhraseScreen.CheckSeedPhrase -> { - analyticsEventHandler.send(SeedPhraseEvents.CheckingScreenOpened) - mediator.allowScreenshots(true) - } - - SeedPhraseScreen.ImportSeedPhrase -> { - analyticsEventHandler.send(SeedPhraseEvents.ImportScreenOpened) - } - } - }.launchIn(viewModelScope) - } - - fun setMediator(mediator: SeedPhraseMediator) { - this.mediator = mediator - } - - fun setCardArtworkUri(cardArtworkUri: String) { - if (uiState.introState.cardImageUrl != cardArtworkUri) { - uiState = uiBuilder.setCardArtwork(uiState, cardArtworkUri) - } - } - - private fun createUiActions(): UiActions = UiActions( - introActions = IntroUiAction( - buttonCreateWalletClick = ::buttonCreateWalletClick, - buttonOtherOptionsClick = ::buttonOtherOptionsClick, - ), - aboutActions = AboutUiAction( - buttonReadMoreAboutSeedPhraseClick = ::buttonReadMoreAboutSeedPhraseClick, - buttonGenerateSeedPhraseClick = ::buttonGenerateSeedPhraseClick, - buttonImportSeedPhraseClick = ::buttonImportSeedPhraseClick, - ), - yourSeedPhraseActions = YourSeedPhraseUiAction( - buttonContinueClick = ::buttonContinueClick, - onSelectType = ::onSelectType, - ), - checkSeedPhraseActions = CheckSeedPhraseUiAction( - buttonCreateWalletClick = { - val mnemonicComponents = - generatedMnemonicComponents[selectedMnemonicType] ?: return@CheckSeedPhraseUiAction - buttonImportWalletClick(mnemonicComponents, null, SeedPhraseSource.GENERATED) - }, - secondTextFieldAction = TextFieldUiAction( - onTextFieldChanged = { value -> onTextFieldChanged(SeedPhraseField.Second, value) }, - ), - seventhTextFieldAction = TextFieldUiAction( - onTextFieldChanged = { value -> onTextFieldChanged(SeedPhraseField.Seventh, value) }, - ), - eleventhTextFieldAction = TextFieldUiAction( - onTextFieldChanged = { value -> onTextFieldChanged(SeedPhraseField.Eleventh, value) }, - ), - ), - importSeedPhraseActions = ImportSeedPhraseUiAction( - phraseTextFieldAction = TextFieldUiAction( - onTextFieldChanged = { value -> onSeedPhraseTextFieldChanged(value) }, - ), - passTextFieldAction = TextFieldUiAction( - onTextFieldChanged = { value -> onPassPhraseTextFieldChanged(value) }, - ), - suggestedPhraseClick = ::buttonSuggestedPhraseClick, - onPassphraseInfoClick = ::buttonPassphraseInfoClick, - buttonCreateWalletClick = { - analyticsEventHandler.send(SeedPhraseEvents.ButtonImport) - buttonImportWalletClick(importedMnemonicComponents, importedPassphrase, SeedPhraseSource.IMPORTED) - }, - ), - menuChatClick = ::menuChatClick, - menuNavigateBackClick = ::menuNavigateBackClick, - ) - - // region CheckSeedPhrase - private fun onTextFieldChanged(field: SeedPhraseField, textFieldValue: TextFieldValue) { - launchSingle { - updateUi { uiBuilder.checkSeedPhrase.updateTextField(uiState, field, textFieldValue) } - - val fieldState = field.getState(uiState) - if (fieldState.textFieldValue.text.isEmpty()) { - updateUi { - val mediate = uiBuilder.checkSeedPhrase.updateTextFieldError(uiState, field, hasError = false) - uiBuilder.checkSeedPhrase.updateCreateWalletButton(mediate, enabled = false) - } - return@launchSingle - } - - createOrGetDebouncer(field.name).debounce(viewModelScope, context = dispatchers.io) { - val mnemonicComponents = generatedMnemonicComponents[selectedMnemonicType] ?: return@debounce - val hasError = !interactor.isWordMatch(mnemonicComponents, field, textFieldValue.text) - if (fieldState.isError != hasError) { - updateUi { uiBuilder.checkSeedPhrase.updateTextFieldError(uiState, field, hasError) } - } - val isCreateWalletButtonEnabled = SeedPhraseField.entries - .map { field -> field.getState(uiState) } - .all { fieldState -> fieldState.textFieldValue.text.isNotEmpty() && !fieldState.isError } - - if (uiState.checkSeedPhraseState.buttonCreateWallet.enabled != isCreateWalletButtonEnabled) { - updateUi { - uiBuilder.checkSeedPhrase.updateCreateWalletButton( - uiState = uiState, - enabled = isCreateWalletButtonEnabled, - ) - } - } - } - } - } - // endregion CheckSeedPhrase - - // region ImportSeedPhrase - private fun onSeedPhraseTextFieldChanged(textFieldValue: TextFieldValue) { - val oldTextFieldValue = uiState.importSeedPhraseState.fieldSeedPhrase.textFieldValue - val isSameText = textFieldValue.text == oldTextFieldValue.text - val isCursorMoved = textFieldValue.selection != oldTextFieldValue.selection - - uiState = uiBuilder.importSeedPhrase.updateSeedPhraseTextField(uiState, textFieldValue) - - val fieldState = uiState.importSeedPhraseState.fieldSeedPhrase - val inputMnemonic = fieldState.textFieldValue.text - - val debouncer = createOrGetDebouncer(MNEMONIC_DEBOUNCER) - when { - isSameText && isCursorMoved -> { - debouncer.debounce(viewModelScope, MNEMONIC_DEBOUNCE_DELAY, dispatchers.single) { - updateSuggestions(fieldState) - } - } - isSameText && !isCursorMoved -> { - // do nothing - } - else -> { - debouncer.debounce(viewModelScope, MNEMONIC_DEBOUNCE_DELAY, dispatchers.single) { - updateSuggestions(fieldState) - validateMnemonic(inputMnemonic) - } - } - } - } - - private fun onPassPhraseTextFieldChanged(textFieldValue: TextFieldValue) { - importedPassphrase = textFieldValue.text - uiState = uiBuilder.importSeedPhrase.updatePassPhraseTextField(uiState, textFieldValue) - } - - private suspend fun validateMnemonic(inputMnemonic: String) { - if (inputMnemonic.isEmpty() && uiState.importSeedPhraseState.error != null) { - val mediateState = uiBuilder.importSeedPhrase.updateCreateWalletButton(uiState, enabled = false) - updateUi { - uiBuilder.importSeedPhrase.updateError(mediateState, null) - } - return - } - - interactor.validateMnemonicString(inputMnemonic) - .onSuccess { mnemonicComponents -> - importedMnemonicComponents = mnemonicComponents - val mediateState = uiBuilder.importSeedPhrase.updateCreateWalletButton(uiState, enabled = true) - updateUi { uiBuilder.importSeedPhrase.updateError(mediateState, null) } - } - .onFailure { - uiState = uiBuilder.importSeedPhrase.updateCreateWalletButton(uiState, enabled = false) - val error = it as? SeedPhraseError ?: return - - importedMnemonicComponents = null - val mediateState = when (error) { - is SeedPhraseError.InvalidWords -> { - uiBuilder.importSeedPhrase.updateInvalidWords(uiState, error.words) - } - else -> uiState - } - updateUi { uiBuilder.importSeedPhrase.updateError(mediateState, error) } - } - } - - private suspend fun updateSuggestions(fieldState: TextFieldState) { - val suggestions = interactor.getSuggestions( - text = fieldState.textFieldValue.text, - hasSelection = !fieldState.textFieldValue.selection.collapsed, - cursorPosition = fieldState.textFieldValue.selection.end, - ) - updateUi { uiBuilder.importSeedPhrase.updateSuggestions(uiState, suggestions) } - } - // endregion ImportSeedPhrase - - // region ButtonClickHandlers - private fun buttonCreateWalletClick() { - viewModelScope.launch(dispatchers.io) { - analyticsEventHandler.send(CreateWalletEvents.OnboardingSeedButtonCreateWallet) - mediator.createWallet(::handleWalletCreationResult) - } - } - - private fun buttonImportWalletClick( - mnemonicComponents: List?, - passphrase: String?, - seedPhraseSource: SeedPhraseSource, - ) { - mnemonicComponents ?: return - - viewModelScope.launch(dispatchers.io) { - mediator.importWallet(mnemonicComponents, passphrase, seedPhraseSource, ::handleWalletCreationResult) - } - } - - private fun handleWalletCreationResult(result: CompletionResult) { - when (result) { - is CompletionResult.Success -> { - isFinished = true - } - is CompletionResult.Failure -> { - // errors shows on the TangemSdk bottom sheet dialog - } - } - mediator.onWalletCreated(result) - } - - private fun menuNavigateBackClick() { - router.navigateBack() - } - - private fun menuChatClick() { - router.openChat() - } - - private fun buttonOtherOptionsClick() { - analyticsEventHandler.send(CreateWalletEvents.OnboardingSeedButtonOtherOptions) - router.openScreen(SeedPhraseScreen.AboutSeedPhrase) - } - - private fun buttonReadMoreAboutSeedPhraseClick() { - analyticsEventHandler.send(SeedPhraseEvents.ButtonReadMore) - val webUri = Uri.Builder() - .scheme("https") - .authority("tangem.com") - .appendPath(localeProvider.getWebUriLocaleLanguage()) - .appendPath("blog/post/seed-phrase-a-risky-solution") - .build() - - router.openUri(webUri) - } - - private fun buttonGenerateSeedPhraseClick() { - val mnemonicTypes = listOf(MnemonicType.Mnemonic12, MnemonicType.Mnemonic24) - analyticsEventHandler.send(SeedPhraseEvents.ButtonGenerateSeedPhrase) - launchSingle { - updateUi { uiBuilder.generateMnemonicComponents(uiState) } - delay(DELAY_GENERATE_SEED_PHRASE) - interactor.generateMnemonics(mnemonicTypes) - .onSuccess { mnemonics -> - generatedMnemonicComponents = mnemonics.mapValues { it.value.mnemonicComponents } - val defaultMnemonic = mnemonics[selectedMnemonicType]?.mnemonicComponents ?: return@launchSingle - val mnemonicGridItems = toMnemonicGridList(defaultMnemonic) - updateUi { - router.openScreen(SeedPhraseScreen.YourSeedPhrase) - uiBuilder.mnemonicGenerated(uiState, mnemonicGridItems.toPersistentList()) - } - } - .onFailure { - generatedMnemonicComponents = emptyMap() - // TODO: show error - } - } - } - - private fun toMnemonicGridList(mnemonicComponents: List): PersistentList { - return mnemonicComponents.mapIndexed { index, word -> - MnemonicGridItem( - index = index.inc(), - mnemonic = word, - ) - }.toPersistentList() - } - - private fun buttonImportSeedPhraseClick() { - analyticsEventHandler.send(SeedPhraseEvents.ButtonImportWallet) - router.openScreen(SeedPhraseScreen.ImportSeedPhrase) - } - - private fun buttonContinueClick() { - launchSingle { - updateUi { - uiBuilder.clearCheckSeedPhraseState(uiState) - } - router.openScreen(SeedPhraseScreen.CheckSeedPhrase) - } - } - - private fun onSelectType(selectedSeedType: SegmentSeedType) { - launchSingle { - selectedMnemonicType = selectedSeedType.toMnemonicType() - val selectedMnemonic = generatedMnemonicComponents[selectedMnemonicType] ?: return@launchSingle - updateUi { - uiBuilder.selectSeedType( - uiState = uiState, - mnemonicGridItems = toMnemonicGridList(selectedMnemonic), - selectedSeedType = selectedSeedType, - ) - } - } - } - - private fun buttonSuggestedPhraseClick(suggestionIndex: Int) { - launchSingle { - val textFieldValue = uiState.importSeedPhraseState.fieldSeedPhrase.textFieldValue - val word = uiState.importSeedPhraseState.suggestionsList[suggestionIndex] - val cursorPosition = textFieldValue.selection.end - - val insertResult = interactor.insertSuggestionWord( - text = textFieldValue.text, - suggestion = word, - cursorPosition = cursorPosition, - ) - updateUi { - val mediateState = uiBuilder.importSeedPhrase.insertSuggestionWord(uiState, insertResult) - uiBuilder.importSeedPhrase.updateSuggestions(mediateState, persistentListOf()) - // copy of TextFieldValue has no effect for textChange callback and seed validation doesn't work - // call validation force - } - validateMnemonic(uiState.importSeedPhraseState.fieldSeedPhrase.textFieldValue.text) - } - } - - private fun buttonPassphraseInfoClick() { - launchSingle { - updateUi { - uiBuilder.importSeedPhrase.showPassphraseInfoBottomSheet(uiState) { - dismissPassphraseBottomSheet() - } - } - } - } - - private fun dismissPassphraseBottomSheet() { - launchSingle { - updateUi { uiBuilder.importSeedPhrase.dismissPassphraseBottomSheet(uiState) } - } - } - // endregion ButtonClickHandlers - - // region Utils - /** - * Updating the UI with a contract where all copying of objects are called in the Single thread context and - * updating the UiState in the main context. - */ - private suspend fun updateUi(updateBlock: suspend () -> OnboardingSeedPhraseState) { - withSingleContext { - val newState = updateBlock.invoke() - withMainContext { uiState = newState } - } - } - - private fun createOrGetDebouncer(name: String): Debouncer { - return textFieldsDebouncers[name] ?: Debouncer().apply { textFieldsDebouncers[name] = this } - } - - private fun SeedPhraseField.getState(uiState: OnboardingSeedPhraseState): TextFieldState = when (this) { - SeedPhraseField.Second -> uiState.checkSeedPhraseState.tvSecondPhrase - SeedPhraseField.Seventh -> uiState.checkSeedPhraseState.tvSeventhPhrase - SeedPhraseField.Eleventh -> uiState.checkSeedPhraseState.tvEleventhPhrase - } - - private fun launchSingle(block: suspend CoroutineScope.() -> Unit): Job { - return viewModelScope.launch(dispatchers.single, block = block) - } - - private suspend fun withMainContext(block: suspend CoroutineScope.() -> T): T { - return withContext(dispatchers.main, block) - } - - private suspend fun withSingleContext(block: suspend CoroutineScope.() -> T): T { - return withContext(dispatchers.single, block) - } - // endregion Utils - - private companion object { - const val MNEMONIC_DEBOUNCER = "MnemonicDebouncer" - const val MNEMONIC_DEBOUNCE_DELAY = 700L - const val DELAY_GENERATE_SEED_PHRASE = 300L - } -} \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt index 33f0abba3e..3ff00087f0 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt @@ -19,8 +19,6 @@ import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.redux.LegacyAction -import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.DeleteWalletUseCase @@ -34,7 +32,6 @@ import com.tangem.feature.walletsettings.entity.WalletSettingsUM import com.tangem.feature.walletsettings.impl.R import com.tangem.feature.walletsettings.utils.ItemsBuilder import com.tangem.features.nft.NFTFeatureToggles -import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf @@ -55,12 +52,10 @@ internal class WalletSettingsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, private val analyticsContextProxy: AnalyticsContextProxy, - private val reduxStateHolder: ReduxStateHolder, private val getShouldSaveUserWalletsSyncUseCase: ShouldSaveUserWalletsSyncUseCase, private val isDemoCardUseCase: IsDemoCardUseCase, private val walletsRepository: WalletsRepository, private val nftFeatureToggles: NFTFeatureToggles, - private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles, ) : Model() { val params: WalletSettingsComponent.Params = paramsContainer.require() @@ -163,23 +158,12 @@ internal class WalletSettingsModel @Inject constructor( analyticsEventHandler.send(Settings.ButtonCreateBackup) analyticsContextProxy.addContext(scanResponse) - if (onboardingV2FeatureToggles.isOnboardingV2Enabled) { - router.push( - AppRoute.Onboarding( - scanResponse = scanResponse, - mode = AppRoute.Onboarding.Mode.AddBackupWallet1, - ), - ) - } else { - reduxStateHolder.dispatch( - LegacyAction.StartOnboardingProcess( - scanResponse = scanResponse, - canSkipBackup = false, - ), - ) - - router.push(AppRoute.OnboardingWallet()) - } + router.push( + AppRoute.Onboarding( + scanResponse = scanResponse, + mode = AppRoute.Onboarding.Mode.AddBackupWallet1, + ), + ) } private fun onCheckedNFTChange(isChecked: Boolean) { diff --git a/features/wallet/impl/build.gradle.kts b/features/wallet/impl/build.gradle.kts index b2a3af1b04..fc42f54104 100644 --- a/features/wallet/impl/build.gradle.kts +++ b/features/wallet/impl/build.gradle.kts @@ -96,9 +96,6 @@ dependencies { implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) - //TODO: Create api/impl modules for onboarding [REDACTED_JIRA] - implementation(projects.features.onboarding) - /** Feature Apis */ implementation(projects.features.details.api) implementation(projects.features.manageTokens.api) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 419db01ebc..cb41f9c60a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -14,8 +14,6 @@ import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher import com.tangem.domain.promo.ShouldShowSwapPromoWalletUseCase -import com.tangem.domain.redux.LegacyAction -import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.settings.NeverToSuggestRateAppUseCase import com.tangem.domain.settings.RemindToRateAppLaterUseCase import com.tangem.domain.tokens.FetchTokenListUseCase @@ -96,7 +94,6 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( private val scanCardToUnlockWalletClickHandler: ScanCardToUnlockWalletClickHandler, private val unlockWalletsUseCase: UnlockWalletsUseCase, private val analyticsEventHandler: AnalyticsEventHandler, - private val reduxStateHolder: ReduxStateHolder, private val dispatchers: CoroutineDispatcherProvider, private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase, private val getCardInfoUseCase: GetCardInfoUseCase, @@ -116,14 +113,6 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( private fun prepareAndStartOnboardingProcess() { modelScope.launch(dispatchers.main) { getSelectedUserWallet()?.let { - reduxStateHolder.dispatch( - LegacyAction.StartOnboardingProcess( - scanResponse = it.scanResponse, - canSkipBackup = false, - ), - ) - - // navigation action shouldn't be out of coroutine to avoid race router.openOnboardingScreen( scanResponse = it.scanResponse, continueBackup = true, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index 2b865d1f61..048f9af182 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -15,7 +15,6 @@ import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.navigation.WalletRoute import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig import com.tangem.features.biometry.BiometryFeatureToggles -import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import javax.inject.Inject @@ -26,7 +25,6 @@ internal class DefaultWalletRouter @Inject constructor( private val router: AppRouter, private val urlOpener: UrlOpener, private val reduxStateHolder: ReduxStateHolder, - private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles, private val biometryFeatureToggles: BiometryFeatureToggles, ) : InnerWalletRouter { @@ -50,22 +48,16 @@ internal class DefaultWalletRouter @Inject constructor( } override fun openOnboardingScreen(scanResponse: ScanResponse, continueBackup: Boolean) { - if (onboardingV2FeatureToggles.isOnboardingV2Enabled) { - router.push( - AppRoute.Onboarding( - scanResponse = scanResponse, - mode = if (continueBackup) { - AppRoute.Onboarding.Mode.AddBackupWallet1 - } else { - AppRoute.Onboarding.Mode.Onboarding - }, - ), - ) - } else { - router.push( - AppRoute.OnboardingWallet(canSkipBackup = false), - ) - } + router.push( + AppRoute.Onboarding( + scanResponse = scanResponse, + mode = if (continueBackup) { + AppRoute.Onboarding.Mode.AddBackupWallet1 + } else { + AppRoute.Onboarding.Mode.Onboarding + }, + ), + ) } override fun openOnrampSuccessScreen(txId: String) { diff --git a/settings.gradle.kts b/settings.gradle.kts index 5aa3d2ba61..385d8b2dc8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -170,7 +170,6 @@ include(":libs:tangem-sdk-api") // endregion Libs modules // region Feature modules -include(":features:onboarding") include(":features:onboarding-v2:api") include(":features:onboarding-v2:impl")