Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-02 11:35:43 +03:00
commit f2bf06648f
31 changed files with 453 additions and 103 deletions

View file

@ -26,6 +26,7 @@ import com.tangem.tap.common.redux.global.GlobalState
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource
import com.tangem.tap.features.saveWallet.redux.SaveWalletAction
import com.tangem.tap.mainScope
import com.tangem.tap.proxy.redux.DaggerGraphState
@ -67,10 +68,21 @@ object OnboardingHelper {
}
fun whereToNavigate(scanResponse: ScanResponse): AppRoute {
if (store.inject(DaggerGraphState::onboardingV2FeatureToggles).isOnboardingV2Enabled) {
val newOnboardingSupportTypes = scanResponse.productType == ProductType.Wallet2 ||
scanResponse.productType == ProductType.Ring ||
scanResponse.productType == ProductType.Wallet
if (store.inject(DaggerGraphState::onboardingV2FeatureToggles).isOnboardingV2Enabled &&
newOnboardingSupportTypes
) {
val backupState = store.state.onboardingWalletState.backupState
return AppRoute.Onboarding(
scanResponse = scanResponse,
startFromBackup = false,
mode = when (backupState.startedSource) {
BackupStartedSource.Onboarding -> AppRoute.Onboarding.Mode.Onboarding
BackupStartedSource.CreateBackup -> AppRoute.Onboarding.Mode.AddBackup
},
)
}

View file

@ -235,6 +235,10 @@ internal class ChildFactory @Inject constructor(
params = OnboardingEntryComponent.Params(
scanResponse = route.scanResponse,
startBackupFlow = route.startFromBackup,
multiWalletMode = when (route.mode) {
AppRoute.Onboarding.Mode.Onboarding -> OnboardingEntryComponent.MultiWalletMode.Onboarding
AppRoute.Onboarding.Mode.AddBackup -> OnboardingEntryComponent.MultiWalletMode.AddBackup
},
),
componentFactory = onboardingEntryComponentFactory,
)

View file

@ -329,5 +329,12 @@ sealed class AppRoute(val path: String) : Route {
data class Onboarding(
val scanResponse: ScanResponse,
val startFromBackup: Boolean,
) : AppRoute(path = "/onboarding_v2${if (startFromBackup) "/backup" else ""}")
val mode: Mode = Mode.Onboarding,
) : AppRoute(path = "/onboarding_v2${if (startFromBackup) "/backup" else ""}") {
enum class Mode {
Onboarding, // general Mode
AddBackup, // continue backup process for existing wallet 1
}
}
}

View file

@ -9,7 +9,13 @@ interface OnboardingEntryComponent : ComposableContentComponent {
data class Params(
val scanResponse: ScanResponse,
val startBackupFlow: Boolean,
val multiWalletMode: MultiWalletMode,
)
enum class MultiWalletMode {
Onboarding,
AddBackup,
}
interface Factory : ComponentFactory<Params, OnboardingEntryComponent>
}

View file

@ -20,7 +20,6 @@ import com.tangem.core.ui.components.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
import kotlinx.coroutines.delay
@Composable
internal fun OnboardingDone(onContinueClick: () -> Unit, modifier: Modifier = Modifier) {
@ -85,7 +84,6 @@ internal fun OnboardingDone(onContinueClick: () -> Unit, modifier: Modifier = Mo
}
LaunchedEffect(Unit) {
delay(timeMillis = 500)
showConfetti = true
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.entry.impl
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@ -48,7 +49,7 @@ internal class DefaultOnboardingEntryComponent @AssistedInject constructor(
popBack = {
popInternal { success ->
if (success.not()) {
model.stackNavigation.pop() // TODO
model.stackNavigation.pop()
}
}
},
@ -126,6 +127,9 @@ internal class DefaultOnboardingEntryComponent @AssistedInject constructor(
override fun Content(modifier: Modifier) {
val innerStackState by innerStack.subscribeAsState()
// prevent back navigation
BackHandler { }
OnboardingEntry(
modifier = modifier,
stepperContent = { modifierParam ->

View file

@ -16,6 +16,7 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.onboarding.v2.TitleProvider
import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent
import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingRoute
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.NonCancellable
@ -46,6 +47,11 @@ internal class OnboardingEntryModel @Inject constructor(
val startRoute = routeByProductType(params.scanResponse)
private fun routeByProductType(scanResponse: ScanResponse): OnboardingRoute {
val multiWalletNavigationMode = when (params.multiWalletMode) {
OnboardingEntryComponent.MultiWalletMode.Onboarding -> OnboardingMultiWalletComponent.Mode.Onboarding
OnboardingEntryComponent.MultiWalletMode.AddBackup -> OnboardingMultiWalletComponent.Mode.AddBackup
}
return when (scanResponse.productType) {
ProductType.Note -> TODO()
ProductType.Twins -> TODO()
@ -54,6 +60,7 @@ internal class OnboardingEntryModel @Inject constructor(
withSeedPhraseFlow = false,
titleProvider = titleProvider,
onDone = ::onMultiWalletOnboardingDone,
mode = multiWalletNavigationMode,
)
ProductType.Ring,
ProductType.Wallet2,
@ -62,6 +69,7 @@ internal class OnboardingEntryModel @Inject constructor(
withSeedPhraseFlow = true,
titleProvider = titleProvider,
onDone = ::onMultiWalletOnboardingDone,
mode = multiWalletNavigationMode,
)
ProductType.Start2Coin -> TODO()
ProductType.Visa -> TODO()

View file

@ -21,6 +21,7 @@ internal class OnboardingChildFactory @Inject constructor(
withSeedPhraseFlow = route.withSeedPhraseFlow,
titleProvider = route.titleProvider,
onDone = route.onDone,
mode = route.mode,
),
)
is OnboardingRoute.ManageTokens -> onboardingManageTokensComponentFactory.create(

View file

@ -4,6 +4,7 @@ import com.tangem.core.decompose.navigation.Route
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.onboarding.v2.TitleProvider
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
sealed class OnboardingRoute : Route {
@ -13,6 +14,7 @@ sealed class OnboardingRoute : Route {
val titleProvider: TitleProvider,
val scanResponse: ScanResponse,
val withSeedPhraseFlow: Boolean,
val mode: OnboardingMultiWalletComponent.Mode,
val onDone: (UserWallet) -> Unit,
) : OnboardingRoute()

View file

@ -13,8 +13,14 @@ interface OnboardingMultiWalletComponent : ComposableContentComponent, InnerNavi
val titleProvider: TitleProvider,
val scanResponse: ScanResponse,
val withSeedPhraseFlow: Boolean,
val mode: Mode,
val onDone: (UserWallet) -> Unit,
)
enum class Mode {
Onboarding,
AddBackup,
}
interface Factory : ComponentFactory<Params, OnboardingMultiWalletComponent>
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@ -17,6 +18,7 @@ import com.arkivanov.decompose.router.slot.navigate
import com.arkivanov.decompose.router.stack.*
import com.arkivanov.decompose.value.Value
import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
@ -24,6 +26,7 @@ import com.tangem.core.decompose.navigation.inner.InnerNavigation
import com.tangem.core.decompose.navigation.inner.InnerNavigationState
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.MultiWalletAccessCodeComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.MultiWalletBackupComponent
@ -45,6 +48,7 @@ import kotlinx.coroutines.launch
internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor(
@Assisted private val context: AppComponentContext,
@Assisted private val params: OnboardingMultiWalletComponent.Params,
private val analyticsHandler: AnalyticsEventHandler,
) : OnboardingMultiWalletComponent, AppComponentContext by context {
private val model: OnboardingMultiWalletModel = getOrCreateModel(params)
@ -70,6 +74,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
multiWalletState = model.state,
parentParams = params,
innerNavigation = innerNavigationStateFlow,
backups = model.backups,
)
private val childStack: Value<ChildStack<OnboardingMultiWalletState.Step, ComposableContentComponent>> =
@ -92,13 +97,10 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
override val state = innerNavigationStateFlow
override fun pop(onComplete: (Boolean) -> Unit) {
when (childStack.active.configuration) {
CreateWallet -> { } // TODO show dialog
ChooseBackupOption -> { } // TODO show dialog
SeedPhrase -> { componentScope.launch { backButtonClickFlow.emit(Unit) } }
AddBackupDevice -> {}
Finalize -> {}
Done -> {}
if (childStack.active.configuration == SeedPhrase) {
componentScope.launch { backButtonClickFlow.emit(Unit) }
} else {
model.onBack()
}
}
}
@ -183,6 +185,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
}
Done -> {
// final step - navigate to parent
analyticsHandler.send(OnboardingEvent.Finished)
val userWallet = childParams.multiWalletState.value.resultUserWallet ?: return
params.onDone(userWallet)
}
@ -237,6 +240,8 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
val state by model.uiState.collectAsStateWithLifecycle()
val artworksState by artworksState.collectAsStateWithLifecycle()
BackHandler { model.onBack() }
OnboardingMultiWallet(
state = state,
modifier = modifier,

View file

@ -0,0 +1,68 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
sealed class OnboardingEvent(
category: String,
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(category, event, params) {
data object Started : OnboardingEvent("Onboarding", "Onboarding Started")
data object Finished : OnboardingEvent("Onboarding", "Onboarding Finished")
sealed class CreateWallet(
event: String,
params: Map<String, String> = mapOf(),
) : OnboardingEvent("Onboarding / Create Wallet", event, params) {
data object ScreenOpened : CreateWallet("Create Wallet Screen Opened")
data object ButtonCreateWallet : CreateWallet("Button - Create Wallet")
class WalletCreatedSuccessfully(
creationType: WalletCreationType = WalletCreationType.PrivateKey,
seedPhraseLength: Int? = null,
) : CreateWallet(
event = "Wallet Created Successfully",
params = buildMap {
put("Creation Type", creationType.value)
if (seedPhraseLength != null) {
put("Seed Phrase Length", seedPhraseLength.toString())
}
},
)
sealed class WalletCreationType(val value: String) {
data object PrivateKey : WalletCreationType(value = "Private Key")
data object NewSeed : WalletCreationType(value = "New Seed")
data object SeedImport : WalletCreationType(value = "Seed Import")
}
}
sealed class Backup(
event: String,
params: Map<String, String> = mapOf(),
) : OnboardingEvent("Onboarding / Backup", event, params) {
data object ScreenOpened : Backup("Backup Screen Opened")
data object Started : Backup("Backup Started")
data object Skipped : Backup("Backup Skipped")
data object SettingAccessCodeStarted : Backup("Setting Access Code Started")
data object AccessCodeEntered : Backup("Access Code Entered")
data object AccessCodeReEntered : Backup("Access Code Re-entered")
class Finished(cardsCount: Int) : Backup(
event = "Backup Finished",
params = mapOf("Cards count" to "$cardsCount"),
)
data object ResetCancelEvent : Backup(
event = "Reset Card Notification",
params = mapOf("Option" to "Cancel"),
)
data object ResetPerformEvent : Backup(
event = "Reset Card Notification",
params = mapOf("Option" to "Reset"),
)
}
}

View file

@ -8,5 +8,34 @@ import kotlinx.coroutines.flow.MutableStateFlow
class MultiWalletChildParams(
val multiWalletState: MutableStateFlow<OnboardingMultiWalletState>,
val innerNavigation: MutableStateFlow<MultiWalletInnerNavigationState>,
val backups: MutableStateFlow<Backup>,
val parentParams: OnboardingMultiWalletComponent.Params,
)
) {
data class Backup(
val card2: BackupCardInfo? = null,
val card3: BackupCardInfo? = null,
) {
data class BackupCardInfo(
val cardId: String,
val cardPublicKey: ByteArray,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as BackupCardInfo
if (cardId != other.cardId) return false
if (!cardPublicKey.contentEquals(other.cardPublicKey)) return false
return true
}
override fun hashCode(): Int {
var result = cardId.hashCode()
result = 31 * result + cardPublicKey.contentHashCode()
return result
}
}
}
}

View file

@ -1,9 +1,11 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.model
import androidx.compose.ui.text.input.TextFieldValue
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.ui.state.MultiWalletAccessCodeUM
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
@ -23,6 +25,7 @@ internal class MultiWalletAccessCodeModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val backupServiceHolder: BackupServiceHolder,
private val analyticsHandler: AnalyticsEventHandler,
) : Model() {
private val _uiState = MutableStateFlow(getInitialState())
@ -32,6 +35,8 @@ internal class MultiWalletAccessCodeModel @Inject constructor(
val onDismiss = MutableSharedFlow<Unit>()
init {
analyticsHandler.send(OnboardingEvent.Backup.SettingAccessCodeStarted)
params.multiWalletState.update {
it.copy(accessCode = null)
}
@ -111,6 +116,8 @@ internal class MultiWalletAccessCodeModel @Inject constructor(
it.copy(atLeast4CharError = true)
}
}
analyticsHandler.send(OnboardingEvent.Backup.AccessCodeEntered)
}
MultiWalletAccessCodeUM.Step.ConfirmAccessCode -> {
if (checkAccessCode()) {
@ -123,6 +130,8 @@ internal class MultiWalletAccessCodeModel @Inject constructor(
}
modelScope.launch { onDismiss.emit(Unit) }
}
analyticsHandler.send(OnboardingEvent.Backup.AccessCodeReEntered)
}
}
}

View file

@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -10,6 +11,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.models.scan.ProductType
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.MultiWalletBackupComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.backupCardAttestationFailedDialog
@ -33,6 +35,7 @@ class MultiWalletBackupModel @Inject constructor(
private val backupServiceHolder: BackupServiceHolder,
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val tangemSdkManager: TangemSdkManager,
private val analyticsHandler: AnalyticsEventHandler,
) : Model() {
@Suppress("UnusedPrivateMember")
@ -57,6 +60,15 @@ class MultiWalletBackupModel @Inject constructor(
val uiState: StateFlow<MultiWalletBackupUM> = _uiState
val eventFlow = MutableSharedFlow<MultiWalletBackupComponent.Event>()
init {
// for wallet 1 this event is sent in Wallet1ChooseOptionModel
if (scanResponse.productType == ProductType.Wallet2 || scanResponse.productType == ProductType.Ring) {
analyticsHandler.send(OnboardingEvent.Backup.ScreenOpened)
}
analyticsHandler.send(OnboardingEvent.Backup.Started)
}
private fun getInitState(): MultiWalletBackupUM {
return when (backupService.currentState) {
BackupService.State.Preparing -> {
@ -73,6 +85,7 @@ class MultiWalletBackupModel @Inject constructor(
},
)
}
// TODO
is BackupService.State.FinalizingBackupCard -> TODO()
BackupService.State.FinalizingPrimaryCard -> TODO()
BackupService.State.Finished -> TODO()
@ -88,9 +101,6 @@ class MultiWalletBackupModel @Inject constructor(
if (primaryCard != null) {
backupService.setPrimaryCard(primaryCard)
addBackupCardWithService()
} else {
// TODO wallet 2 ??? or from main?
// BackupAction.StartAddingPrimaryCard
}
}
@ -145,6 +155,8 @@ class MultiWalletBackupModel @Inject constructor(
}
}
modelScope.launch { eventFlow.emit(MultiWalletBackupComponent.Event.Done) }
analyticsHandler.send(OnboardingEvent.Backup.Finished(cardsCount = state.value.backupCardsNumber + 1))
}
private fun addBackupCardWithService() {
@ -167,6 +179,18 @@ class MultiWalletBackupModel @Inject constructor(
backupCardsNumber = it.backupCardsNumber + 1,
)
}
val backupCardInfo = MultiWalletChildParams.Backup.BackupCardInfo(
cardId = result.data.cardId,
cardPublicKey = result.data.cardPublicKey,
)
params.backups.update {
it.copy(
card2 = if (state.value.backupCardsNumber == 1) backupCardInfo else it.card2,
card3 = if (state.value.backupCardsNumber == 2) backupCardInfo else it.card3,
)
}
setNumberOfBackupCards(state.value.backupCardsNumber)
}
is CompletionResult.Failure -> {
@ -176,7 +200,12 @@ class MultiWalletBackupModel @Inject constructor(
st.copy(
dialog = resetBackupCardDialog(
onReset = { resetBackupCard(cardId = error.cardId) },
onDismiss = { _uiState.update { it.copy(dialog = null) } },
onDismiss = {
_uiState.update { it.copy(dialog = null) }
},
onDismissClick = {
analyticsHandler.send(OnboardingEvent.Backup.ResetCancelEvent)
},
),
)
}
@ -198,6 +227,8 @@ class MultiWalletBackupModel @Inject constructor(
}
private fun resetBackupCard(cardId: String) {
analyticsHandler.send(OnboardingEvent.Backup.ResetPerformEvent)
modelScope.launch {
tangemSdkManager.resetToFactorySettings(
cardId = cardId,

View file

@ -4,16 +4,20 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state.MultiWalletBackupUMDialog
internal fun resetBackupCardDialog(onReset: () -> Unit, onDismiss: () -> Unit) = MultiWalletBackupUMDialog(
title = resourceReference(R.string.common_attention),
bodyText = resourceReference(R.string.onboarding_linking_error_card_with_wallets),
confirmText = resourceReference(R.string.common_cancel),
cancelText = resourceReference(R.string.card_settings_action_sheet_reset),
warningCancelColor = true,
onDismiss = onDismiss,
onConfirm = onDismiss,
onCancel = { onReset(); onDismiss() },
)
internal fun resetBackupCardDialog(onReset: () -> Unit, onDismiss: () -> Unit, onDismissClick: () -> Unit) =
MultiWalletBackupUMDialog(
title = resourceReference(R.string.common_attention),
bodyText = resourceReference(R.string.onboarding_linking_error_card_with_wallets),
confirmText = resourceReference(R.string.common_cancel),
cancelText = resourceReference(R.string.card_settings_action_sheet_reset),
warningCancelColor = true,
onDismiss = {
onDismiss()
onDismissClick()
},
onConfirm = onDismiss,
onCancel = { onReset(); onDismiss() },
)
internal fun backupCardAttestationFailedDialog(onDismiss: () -> Unit) = MultiWalletBackupUMDialog(
title = resourceReference(R.string.common_error),

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.model
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -9,6 +10,7 @@ import com.tangem.domain.wallets.builder.UserWalletBuilder
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
@ -23,18 +25,25 @@ internal class Wallet1ChooseOptionModel @Inject constructor(
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
private val cardRepository: CardRepository,
private val saveWalletUseCase: SaveWalletUseCase,
private val analyticsHandler: AnalyticsEventHandler,
) : Model() {
private val params = paramsContainer.require<MultiWalletChildParams>()
private var skipClicked = false
val returnToParentFlow = MutableSharedFlow<Unit>()
init {
analyticsHandler.send(OnboardingEvent.Backup.ScreenOpened)
}
fun onSkipClick() {
// TODO show confirmation dialog
if (skipClicked) return
skipClicked = true
analyticsHandler.send(OnboardingEvent.Backup.Skipped)
modelScope.launch {
val scanResponse = params.multiWalletState.value.currentScanResponse

View file

@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.mo
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -11,6 +12,7 @@ import com.tangem.domain.feedback.GetCardInfoUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.state.MultiWalletCreateWalletUM
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.resetCardDialog
@ -24,6 +26,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@Suppress("LongParameterList")
@ComponentScoped
internal class MultiWalletCreateWalletModel @Inject constructor(
paramsContainer: ParamsContainer,
@ -32,6 +35,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val getCardInfoUseCase: GetCardInfoUseCase,
private val cardRepository: CardRepository,
private val analyticsHandler: AnalyticsEventHandler,
) : Model() {
private val params = paramsContainer.require<MultiWalletChildParams>()
@ -50,7 +54,10 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
} else {
resourceReference(R.string.onboarding_create_wallet_body)
},
onCreateWalletClick = { createWallet(false) },
onCreateWalletClick = {
analyticsHandler.send(OnboardingEvent.CreateWallet.ButtonCreateWallet)
createWallet(false)
},
showOtherOptionsButton = params.parentParams.withSeedPhraseFlow,
onOtherOptionsClick = {
modelScope.launch {
@ -64,6 +71,10 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
val uiState: StateFlow<MultiWalletCreateWalletUM> = _uiState
val onDone = MutableSharedFlow<OnboardingMultiWalletState.Step>()
init {
analyticsHandler.send(OnboardingEvent.CreateWallet.ScreenOpened)
}
private fun createWallet(shouldReset: Boolean) {
modelScope.launch {
val result = tangemSdkManager.createProductWallet(
@ -91,8 +102,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
onDone.emit(OnboardingMultiWalletState.Step.ChooseBackupOption)
}
// TODO
// Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully())
analyticsHandler.send(OnboardingEvent.CreateWallet.WalletCreatedSuccessfully())
}
is CompletionResult.Failure -> {

View file

@ -17,6 +17,7 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.MultiWalletFinalizeComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.ui.state.MultiWalletFinalizeUM
@ -78,7 +79,7 @@ internal class MultiWalletFinalizeModel @Inject constructor(
private fun writePrimaryCard() {
val backupService = backupServiceHolder.backupService.get() ?: return
// store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing))
// TODO store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing))
val primaryCardBatchId = backupService.primaryCardBatchId ?: return
val isRing = isRing(primaryCardBatchId)
@ -107,7 +108,7 @@ internal class MultiWalletFinalizeModel @Inject constructor(
private fun writeBackupCard(cardIndex: Int) {
val backupService = backupServiceHolder.backupService.get() ?: return
// store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing))
// TODO store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing))
val backupCardBatchId = backupService.backupCardsBatchIds.getOrNull(cardIndex) ?: return
val isRing = isRing(backupCardBatchId)
@ -119,7 +120,6 @@ internal class MultiWalletFinalizeModel @Inject constructor(
is CompletionResult.Success -> {
val backupValidator = BackupValidator()
if (backupValidator.isValidBackupStatus(CardDTO(result.data)).not()) {
// TODO store.dispatchOnMain(BackupAction.ErrorInBackupCard)
walletHasBackupError = true
}
@ -155,43 +155,36 @@ internal class MultiWalletFinalizeModel @Inject constructor(
modelScope.launch {
val scanResponse = params.multiWalletState.value.currentScanResponse
val userWallet = createUserWallet(scanResponse)
userWalletsListManager.save(
userWallet = userWallet.copy(
scanResponse = scanResponse.updateScanResponseAfterBackup(),
),
canOverride = true,
)
// TODO
// BackupStartedSource.CreateBackup -> updateWallet(
// userWalletsListManager = userWalletsListManager,
// userWallet = userWallet,
// backupState = backupState,
// )
// TODO maybe here we should check for backup cards activation status
// 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)
// delay(1000)
// store.dispatchWithMain(BackupAction.BackupFinished(userWalletId = userWallet?.walletId))
cardRepository.finishCardActivation(scanResponse.card.cardId)
when (params.parentParams.mode) {
OnboardingMultiWalletComponent.Mode.Onboarding -> {
userWalletsListManager.save(
userWallet = userWallet.copy(
scanResponse = scanResponse.updateScanResponseAfterBackup(),
),
canOverride = true,
)
}
OnboardingMultiWalletComponent.Mode.AddBackup -> {
userWalletsListManager.update(
userWalletId = userWallet.walletId,
update = { wallet ->
wallet.copy(
scanResponse = scanResponse.updateScanResponseAfterBackup(),
)
},
)
}
}
// save user wallet for manage tokens screen
params.multiWalletState.update {
it.copy(resultUserWallet = userWallet)
}
cardRepository.finishCardActivation(scanResponse.card.cardId)
onEvent.emit(MultiWalletFinalizeComponent.Event.ThreeBackupCardsAdded)
}
}
@ -218,8 +211,8 @@ internal class MultiWalletFinalizeModel @Inject constructor(
}
private fun handleActivationError() {
_uiState.update {
it.copy(
_uiState.update { st ->
st.copy(
dialog = resetCardDialog(
onConfirm = ::navigateToSupportScreen,
dismiss = { _uiState.update { it.copy(dialog = null) } },

View file

@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.mode
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -11,6 +12,7 @@ import com.tangem.domain.card.repository.CardRepository
import com.tangem.domain.feedback.GetCardInfoUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.builder.GenerateSeedPhraseUiStateBuilder
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.builder.ImportSeedPhraseUiStateBuilder
@ -41,6 +43,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
private val cardRepository: CardRepository,
private val getCardInfoUseCase: GetCardInfoUseCase,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val analyticsHandler: AnalyticsEventHandler,
) : Model() {
private val params = paramsContainer.require<MultiWalletChildParams>()
@ -76,6 +79,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
state.value.generatedWords12 ?: return@importWallet
},
passphrase = null,
generatedSeedPhrase = true,
)
},
// =============================================
@ -85,7 +89,13 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
modelScope = modelScope,
mnemonicRepository = mnemonicRepository,
updateUiState = { block -> updateUiStateSpecific(block) },
importWallet = ::importWallet,
importWallet = { mnemonic, passphrase ->
importWallet(
mnemonic = mnemonic,
passphrase = passphrase,
generatedSeedPhrase = false,
)
},
)
val uiState = _uiState.asStateFlow()
@ -159,7 +169,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
// =============================================
// | DON'T FIXME !!! MODIFY WITH CAUTION !!! |
// =============================================
private fun importWallet(mnemonic: Mnemonic, passphrase: String?) {
private fun importWallet(mnemonic: Mnemonic, passphrase: String?, generatedSeedPhrase: Boolean) {
val currentState = state.value
if (currentState.readyToImport.not()) return
@ -175,7 +185,17 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
when (result) {
is CompletionResult.Success -> {
// TODO on success send analytics event
analyticsHandler.send(
OnboardingEvent.CreateWallet.WalletCreatedSuccessfully(
creationType = if (generatedSeedPhrase) {
OnboardingEvent.CreateWallet.WalletCreationType.NewSeed
} else {
OnboardingEvent.CreateWallet.WalletCreationType.SeedImport
},
seedPhraseLength = mnemonic.mnemonicComponents.size,
),
)
multiWalletState.update {
it.copy(
currentScanResponse = it.currentScanResponse.copy(

View file

@ -19,4 +19,20 @@ internal fun resetCardDialog(onConfirm: () -> Unit, dismiss: () -> Unit, onDismi
onDismissButtonClick()
dismiss()
},
)
)
internal fun interruptBackupDialog(onConfirm: () -> Unit, dismiss: () -> Unit) = OnboardingDialogUM(
title = resourceReference(R.string.onboarding_exit_alert_title),
message = resourceReference(R.string.onboarding_exit_alert_message),
confirmButtonText = resourceReference(R.string.common_ok),
dismissButtonText = resourceReference(R.string.common_cancel),
dismissWarningColor = true,
onDismiss = dismiss,
onConfirmClick = {
onConfirm()
dismiss()
},
onDismissButtonClick = {
dismiss()
},
)

View file

@ -1,11 +1,16 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.model
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.interruptBackupDialog
import com.tangem.features.onboarding.v2.multiwallet.impl.ui.state.OnboardingMultiWalletUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.*
@ -16,6 +21,8 @@ import javax.inject.Inject
internal class OnboardingMultiWalletModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val router: Router,
private val analyticsHandler: AnalyticsEventHandler,
) : Model() {
private val params = paramsContainer.require<OnboardingMultiWalletComponent.Params>()
private val getCardImageUseCase = GetCardImageUseCase()
@ -30,16 +37,50 @@ internal class OnboardingMultiWalletModel @Inject constructor(
resultUserWallet = null,
),
)
val backups = MutableStateFlow(MultiWalletChildParams.Backup())
val uiState = _uiState.asStateFlow()
init {
// TODO add analytics
// if (!manager.isActivationStarted(notNullCard.cardId)) {
// Analytics.send(Onboarding.Started())
// }
initScreenTitleSub()
analyticsHandler.send(OnboardingEvent.Started)
initScreenTitle()
loadCardArtwork()
subscribeToBackups()
}
fun onBack() {
_uiState.update {
it.copy(
dialog = interruptBackupDialog(
onConfirm = {
router.pop()
},
dismiss = { _uiState.update { it.copy(dialog = null) } },
),
)
}
}
private fun subscribeToBackups() {
modelScope.launch {
backups.collectLatest { bst ->
when {
_uiState.value.artwork2Url == null && bst.card2 != null -> {
val artwork =
getCardImageUseCase.invoke(bst.card2.cardId, bst.card2.cardPublicKey)
_uiState.update {
it.copy(artwork2Url = artwork)
}
}
_uiState.value.artwork3Url == null && bst.card3 != null -> {
val artwork =
getCardImageUseCase.invoke(bst.card3.cardId, bst.card3.cardPublicKey)
_uiState.update {
it.copy(artwork3Url = artwork)
}
}
}
}
}
}
private fun getInitialStep(): OnboardingMultiWalletState.Step {
@ -56,17 +97,9 @@ internal class OnboardingMultiWalletModel @Inject constructor(
}
}
private fun initScreenTitleSub() {
private fun initScreenTitle() {
val title = screenTitleByStep(getInitialStep())
params.titleProvider.changeTitle(title)
modelScope.launch {
state.map { it.currentStep }
.collectLatest { step ->
val stepTitle = screenTitleByStep(step)
params.titleProvider.changeTitle(stepTitle)
}
}
}
private fun loadCardArtwork() {
@ -76,7 +109,7 @@ internal class OnboardingMultiWalletModel @Inject constructor(
if (artwork != getCardImageUseCase.getDefaultFallbackUrl()) {
_uiState.update {
it.copy(artworkUrl = artwork)
it.copy(artwork1Url = artwork)
}
}
}

View file

@ -8,6 +8,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.multiwallet.impl.ui.state.OnboardingMultiWalletUM
@ -20,12 +23,31 @@ internal fun OnboardingMultiWallet(
modifier: Modifier = Modifier,
childContent: @Composable (Modifier) -> Unit = {},
) {
if (state.dialog != null) {
BasicDialog(
title = state.dialog.title.resolveReference(),
message = state.dialog.message.resolveReference(),
confirmButton = DialogButtonUM(
title = state.dialog.confirmButtonText.resolveReference(),
onClick = state.dialog.onConfirmClick,
),
dismissButton = DialogButtonUM(
title = state.dialog.dismissButtonText.resolveReference(),
warning = state.dialog.dismissWarningColor,
onClick = state.dialog.onDismissButtonClick,
),
onDismissDialog = state.dialog.onDismiss,
)
}
Column(
modifier = modifier.fillMaxSize(),
) {
if (isSeedPhraseState.not()) {
WalletArtworks(
url = state.artworkUrl,
url1 = state.artwork1Url,
url2 = state.artwork2Url,
url3 = state.artwork3Url,
modifier = Modifier
.weight(.56f)
.padding(horizontal = 34.dp)
@ -51,7 +73,7 @@ internal fun OnboardingMultiWallet(
private fun Preview() {
TangemThemePreview {
OnboardingMultiWallet(
state = OnboardingMultiWalletUM(artworkUrl = null),
state = OnboardingMultiWalletUM(artwork1Url = null),
artworksState = WalletArtworksState.Folded,
isSeedPhraseState = false,
childContent = { md ->
@ -71,7 +93,7 @@ private fun Preview() {
private fun Preview2() {
TangemThemePreview {
OnboardingMultiWallet(
state = OnboardingMultiWalletUM(artworkUrl = null),
state = OnboardingMultiWalletUM(artwork1Url = null),
artworksState = WalletArtworksState.Folded,
isSeedPhraseState = true,
childContent = { md ->

View file

@ -58,7 +58,13 @@ sealed class WalletArtworksState {
}
@Composable
fun WalletArtworks(url: String?, state: WalletArtworksState, modifier: Modifier = Modifier) {
fun WalletArtworks(
url1: String?,
url2: String?,
url3: String?,
state: WalletArtworksState,
modifier: Modifier = Modifier,
) {
if (state is WalletArtworksState.Hidden) return
BoxWithConstraints(
@ -116,7 +122,9 @@ fun WalletArtworks(url: String?, state: WalletArtworksState, modifier: Modifier
}
AnimatedWalletCards(
url = url,
url1 = url1,
url2 = url2,
url3 = url3,
modifier = Modifier
.widthIn(max = 450.dp)
.matchParentSize(),
@ -143,9 +151,12 @@ private data class WalletCardTransitionState(
val zIndex: Float = 0f,
)
@Suppress("LongParameterList")
@Composable
private fun AnimatedWalletCards(
url: String?,
url1: String?,
url2: String?,
url3: String?,
transition1: Transition<WalletCardTransitionState>,
transition2: Transition<WalletCardTransitionState>,
transition3: Transition<WalletCardTransitionState>,
@ -190,7 +201,7 @@ private fun AnimatedWalletCards(
scaleY = scaleY3
rotationZ = rotation3
},
url = url,
url = url3,
)
WalletCard(
@ -208,7 +219,7 @@ private fun AnimatedWalletCards(
scaleX = scaleX2
scaleY = scaleY2
},
url = url,
url = url2,
)
WalletCard(
@ -225,7 +236,7 @@ private fun AnimatedWalletCards(
translationY = translationY1
rotationZ = rotation1
},
url = url,
url = url1,
)
}
}
@ -450,7 +461,9 @@ private fun Preview() {
var state: WalletArtworksState by remember { mutableStateOf(WalletArtworksState.Folded) }
WalletArtworks(
url = null,
url1 = null,
url2 = null,
url3 = null,
state = state,
modifier = Modifier.fillMaxWidth(),
)

View file

@ -1,5 +1,10 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.ui.state
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.OnboardingDialogUM
internal data class OnboardingMultiWalletUM(
val artworkUrl: String? = null,
val artwork1Url: String? = null,
val artwork2Url: String? = null,
val artwork3Url: String? = null,
val dialog: OnboardingDialogUM? = null,
)

View file

@ -6,6 +6,8 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.domain.feedback.GetCardInfoUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
@ -23,11 +25,19 @@ internal class DefaultOnboardingStepperComponent @AssistedInject constructor(
@Assisted val params: OnboardingStepperComponent.Params,
private val getCardInfoUseCase: GetCardInfoUseCase,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val analyticsHandler: AnalyticsEventHandler,
) : OnboardingStepperComponent, AppComponentContext by context {
override val state = instanceKeeper.getOrCreateSimple { MutableStateFlow(params.initState) }
private fun openSupport() {
analyticsHandler.send(
AnalyticsEvent(
category = "Onboarding",
event = "Button - Chat",
),
)
componentScope.launch {
val cardInfo = getCardInfoUseCase(params.scanResponse).getOrNull() ?: return@launch
sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo))

View file

@ -95,6 +95,7 @@ dependencies {
implementation(projects.features.pushNotifications.api)
implementation(projects.features.markets.api)
implementation(projects.features.onramp.api)
implementation(projects.features.onboardingV2.api)
/** Common modules */
implementation(projects.common.ui)

View file

@ -4,6 +4,7 @@ import com.tangem.common.routing.AppRouter
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.feature.wallet.presentation.router.DefaultWalletRouter
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
import com.tangem.features.wallet.navigation.WalletRouter
import dagger.Module
import dagger.Provides
@ -21,7 +22,8 @@ internal object WalletRouterModule {
appRouter: AppRouter,
urlOpener: UrlOpener,
reduxStateHolder: ReduxStateHolder,
onboardingV2FeatureToggles: OnboardingV2FeatureToggles,
): WalletRouter {
return DefaultWalletRouter(appRouter, urlOpener, reduxStateHolder)
return DefaultWalletRouter(appRouter, urlOpener, reduxStateHolder, onboardingV2FeatureToggles)
}
}

View file

@ -17,6 +17,7 @@ import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRoute.ManageTokens.Source
import com.tangem.common.routing.AppRouter
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.redux.StateDialog
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
@ -27,6 +28,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensViewM
import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletViewModel
import com.tangem.features.markets.entry.MarketsEntryComponent
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
import kotlin.properties.Delegates
/** Default implementation of wallet feature router */
@ -34,6 +36,7 @@ internal class DefaultWalletRouter(
private val router: AppRouter,
private val urlOpener: UrlOpener,
private val reduxStateHolder: ReduxStateHolder,
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles,
) : InnerWalletRouter {
private var navController: NavHostController by Delegates.notNull()
@ -106,10 +109,24 @@ internal class DefaultWalletRouter(
)
}
override fun openOnboardingScreen() {
router.push(
AppRoute.OnboardingWallet(canSkipBackup = false),
)
override fun openOnboardingScreen(scanResponse: ScanResponse, continueBackup: Boolean) {
if (onboardingV2FeatureToggles.isOnboardingV2Enabled) {
router.push(
AppRoute.Onboarding(
scanResponse = scanResponse,
startFromBackup = true,
mode = if (continueBackup) {
AppRoute.Onboarding.Mode.AddBackup
} else {
AppRoute.Onboarding.Mode.Onboarding
},
),
)
} else {
router.push(
AppRoute.OnboardingWallet(canSkipBackup = false),
)
}
}
override fun openOnrampSuccessScreen(txId: String) {

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.router
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.markets.entry.MarketsEntryComponent
@ -36,7 +37,7 @@ internal interface InnerWalletRouter : WalletRouter {
fun openDetailsScreen(selectedWalletId: UserWalletId)
/** Open onboarding screen */
fun openOnboardingScreen()
fun openOnboardingScreen(scanResponse: ScanResponse, continueBackup: Boolean = false)
/** Open onramp success screen for [txId] */
fun openOnrampSuccessScreen(txId: String)

View file

@ -104,9 +104,13 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
canSkipBackup = false,
),
)
// navigation action shouldn't be out of coroutine to avoid race
router.openOnboardingScreen(
scanResponse = it.scanResponse,
continueBackup = true,
)
}
// navigation action shouldn't be out of coroutine to avoid race
router.openOnboardingScreen()
}
}