Updated on 2026-08-14
This commit is contained in:
parent
a284c8d311
commit
7d017162cb
22 changed files with 554 additions and 111 deletions
|
|
@ -14,6 +14,7 @@ android {
|
|||
dependencies {
|
||||
/** Api */
|
||||
implementation(projects.features.onboardingV2.api)
|
||||
implementation(projects.features.manageTokens.api)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.core.featuretoggles)
|
||||
|
|
@ -34,6 +35,8 @@ dependencies {
|
|||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.legacy)
|
||||
|
||||
/** Tangem libraries */
|
||||
implementation(projects.libs.tangemSdkApi)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.arkivanov.decompose.router.stack.*
|
||||
import com.arkivanov.decompose.value.Value
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
|
|
@ -51,20 +48,18 @@ internal class DefaultOnboardingEntryComponent @AssistedInject constructor(
|
|||
popBack = {
|
||||
popInternal { success ->
|
||||
if (success.not()) {
|
||||
stackNavigation.pop()
|
||||
model.stackNavigation.pop() // TODO
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
private val stackNavigation = StackNavigation<OnboardingRoute>()
|
||||
|
||||
private val innerStack: Value<ChildStack<OnboardingRoute, Any>> = childStack(
|
||||
key = "innerStack",
|
||||
source = stackNavigation,
|
||||
source = model.stackNavigation,
|
||||
serializer = null,
|
||||
initialConfiguration = model.state.value.currentRoute,
|
||||
initialConfiguration = model.startRoute,
|
||||
handleBackButton = true,
|
||||
childFactory = { configuration, factoryContext ->
|
||||
onboardingChildFactory.createChild(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.features.onboarding.v2.entry.impl.model
|
||||
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.navigate
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -7,9 +9,9 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
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.entry.OnboardingEntryComponent
|
||||
import com.tangem.features.onboarding.v2.entry.impl.model.state.OnboardingState
|
||||
import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingRoute
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -23,6 +25,7 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
|
||||
private val params = paramsContainer.require<OnboardingEntryComponent.Params>()
|
||||
|
||||
val stackNavigation = StackNavigation<OnboardingRoute>()
|
||||
val titleProvider = object : TitleProvider {
|
||||
override val currentTitle = MutableStateFlow(stringReference(""))
|
||||
override fun changeTitle(text: TextReference) {
|
||||
|
|
@ -30,11 +33,7 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
val state = MutableStateFlow(
|
||||
OnboardingState(
|
||||
currentRoute = routeByProductType(params.scanResponse),
|
||||
),
|
||||
)
|
||||
val startRoute = routeByProductType(params.scanResponse)
|
||||
|
||||
private fun routeByProductType(scanResponse: ScanResponse): OnboardingRoute {
|
||||
return when (scanResponse.productType) {
|
||||
|
|
@ -44,15 +43,24 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
scanResponse = scanResponse,
|
||||
withSeedPhraseFlow = false,
|
||||
titleProvider = titleProvider,
|
||||
onDone = ::onMultiWalletOnboardingDone,
|
||||
)
|
||||
ProductType.Wallet2 -> OnboardingRoute.MultiWallet(
|
||||
ProductType.Ring,
|
||||
ProductType.Wallet2,
|
||||
-> OnboardingRoute.MultiWallet(
|
||||
scanResponse = scanResponse,
|
||||
withSeedPhraseFlow = true,
|
||||
titleProvider = titleProvider,
|
||||
onDone = ::onMultiWalletOnboardingDone,
|
||||
)
|
||||
ProductType.Start2Coin -> TODO()
|
||||
ProductType.Ring -> TODO()
|
||||
ProductType.Visa -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onMultiWalletOnboardingDone(userWallet: UserWallet) {
|
||||
stackNavigation.navigate {
|
||||
listOf(OnboardingRoute.ManageTokens(userWallet))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
package com.tangem.features.onboarding.v2.entry.impl.routing
|
||||
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class OnboardingChildFactory @Inject constructor(
|
||||
private val multiWalletComponentFactory: OnboardingMultiWalletComponent.Factory,
|
||||
private val manageTokensComponentFactory: ManageTokensComponent.Factory,
|
||||
) {
|
||||
|
||||
fun createChild(route: OnboardingRoute, childContext: AppComponentContext): Any {
|
||||
|
|
@ -16,6 +19,14 @@ internal class OnboardingChildFactory @Inject constructor(
|
|||
scanResponse = route.scanResponse,
|
||||
withSeedPhraseFlow = route.withSeedPhraseFlow,
|
||||
titleProvider = route.titleProvider,
|
||||
onDone = route.onDone,
|
||||
),
|
||||
)
|
||||
is OnboardingRoute.ManageTokens -> manageTokensComponentFactory.create( // TODO replace with wrapper
|
||||
context = childContext,
|
||||
params = ManageTokensComponent.Params(
|
||||
userWalletId = route.userWallet.walletId,
|
||||
source = ManageTokensSource.ONBOARDING,
|
||||
),
|
||||
)
|
||||
else -> Unit
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.entry.impl.routing
|
|||
|
||||
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
|
||||
|
||||
sealed class OnboardingRoute : Route {
|
||||
|
|
@ -12,5 +13,10 @@ sealed class OnboardingRoute : Route {
|
|||
val titleProvider: TitleProvider,
|
||||
val scanResponse: ScanResponse,
|
||||
val withSeedPhraseFlow: Boolean,
|
||||
val onDone: (UserWallet) -> Unit,
|
||||
) : OnboardingRoute()
|
||||
|
||||
data class ManageTokens(
|
||||
val userWallet: UserWallet,
|
||||
) : OnboardingRoute()
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children
|
|||
import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.slide
|
||||
import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingRoute
|
||||
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
|
|
@ -36,6 +37,11 @@ internal inline fun OnboardingEntry(
|
|||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
is OnboardingRoute.ManageTokens -> {
|
||||
(it.instance as ComposableContentComponent).Content(
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
OnboardingRoute.None -> {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.core.decompose.factory.ComponentFactory
|
|||
import com.tangem.core.decompose.navigation.inner.InnerNavigationHolder
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.onboarding.v2.TitleProvider
|
||||
|
||||
interface OnboardingMultiWalletComponent : ComposableContentComponent, InnerNavigationHolder {
|
||||
|
|
@ -12,6 +13,7 @@ interface OnboardingMultiWalletComponent : ComposableContentComponent, InnerNavi
|
|||
val titleProvider: TitleProvider,
|
||||
val scanResponse: ScanResponse,
|
||||
val withSeedPhraseFlow: Boolean,
|
||||
val onDone: (UserWallet) -> Unit,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, OnboardingMultiWalletComponent>
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
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.child.MultiWalletChildComponent
|
||||
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
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.Wallet1ChooseOptionComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.MultiWalletCreateWalletComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.MultiWalletFinalizeComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.MultiWalletSeedPhraseComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
|
||||
|
|
@ -77,7 +78,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
}
|
||||
}
|
||||
|
||||
private val childStack: Value<ChildStack<OnboardingMultiWalletState.Step, MultiWalletChildComponent>> =
|
||||
private val childStack: Value<ChildStack<OnboardingMultiWalletState.Step, ComposableContentComponent>> =
|
||||
childStack(
|
||||
key = "innerStack",
|
||||
source = stackNavigation,
|
||||
|
|
@ -109,26 +110,23 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
init {
|
||||
componentScope.launch {
|
||||
// access code bs result
|
||||
// TODO delete and use callback
|
||||
childParams.multiWalletState
|
||||
.map { it.accessCode }
|
||||
.distinctUntilChanged()
|
||||
.filter { it != null }
|
||||
.collectLatest { handleNavigationEvent(Finalize) }
|
||||
}
|
||||
bottomSheetNavigation.navigate {}
|
||||
}
|
||||
|
||||
private fun createChild(
|
||||
step: OnboardingMultiWalletState.Step,
|
||||
childContext: AppComponentContext,
|
||||
): MultiWalletChildComponent {
|
||||
): ComposableContentComponent {
|
||||
return when (step) {
|
||||
CreateWallet -> MultiWalletCreateWalletComponent(
|
||||
context = childContext,
|
||||
params = MultiWalletChildParams(
|
||||
multiWalletState = model.state,
|
||||
parentParams = params,
|
||||
),
|
||||
params = childParams,
|
||||
onNextStep = ::handleNavigationEvent,
|
||||
)
|
||||
ChooseBackupOption -> Wallet1ChooseOptionComponent(
|
||||
|
|
@ -137,23 +135,21 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
)
|
||||
SeedPhrase -> MultiWalletSeedPhraseComponent(
|
||||
context = childContext,
|
||||
params = MultiWalletChildParams(
|
||||
multiWalletState = model.state,
|
||||
parentParams = params,
|
||||
),
|
||||
params = childParams,
|
||||
onNextStep = ::handleNavigationEvent,
|
||||
backButtonClickFlow = MutableSharedFlow(),
|
||||
backButtonClickFlow = MutableSharedFlow(), // TODO
|
||||
)
|
||||
AddBackupDevice -> MultiWalletBackupComponent(
|
||||
context = childContext,
|
||||
params = MultiWalletChildParams(
|
||||
multiWalletState = model.state,
|
||||
parentParams = params,
|
||||
),
|
||||
params = childParams,
|
||||
onEvent = ::handleBackupComponentEvent,
|
||||
)
|
||||
Finalize -> TODO()
|
||||
Done -> TODO()
|
||||
Finalize -> MultiWalletFinalizeComponent(
|
||||
context = childContext,
|
||||
params = childParams,
|
||||
onEvent = ::handleFinalizeComponentEvent,
|
||||
)
|
||||
Done -> error("Unexpected Done state")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,15 +158,17 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
ChooseBackupOption -> {
|
||||
artworksState.value = WalletArtworksState.Fan
|
||||
}
|
||||
SeedPhrase -> {}
|
||||
AddBackupDevice -> {
|
||||
artworksState.value = WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.First)
|
||||
}
|
||||
Finalize -> {
|
||||
artworksState.value = WalletArtworksState.Stack()
|
||||
artworksState.value = WalletArtworksState.Stack(threeCards = model.state.value.isThreeCards)
|
||||
}
|
||||
Done -> {
|
||||
// TODO
|
||||
// final step - navigate to parent
|
||||
val userWallet = childParams.multiWalletState.value.resultUserWallet ?: return
|
||||
params.onDone(userWallet)
|
||||
return
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
|
|
@ -179,19 +177,44 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
|
||||
private fun handleBackupComponentEvent(event: MultiWalletBackupComponent.Event) {
|
||||
when (event) {
|
||||
MultiWalletBackupComponent.Event.Done -> {
|
||||
artworksState.value = WalletArtworksState.Stack()
|
||||
bottomSheetNavigation.navigate { }
|
||||
}
|
||||
MultiWalletBackupComponent.Event.OneDeviceAdded -> {
|
||||
artworksState.value = WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.Second)
|
||||
}
|
||||
MultiWalletBackupComponent.Event.TwoDeviceAdded -> {
|
||||
artworksState.value = WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.Third)
|
||||
}
|
||||
MultiWalletBackupComponent.Event.Done -> {
|
||||
openAccessCodeBottomSheet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFinalizeComponentEvent(event: MultiWalletFinalizeComponent.Event) {
|
||||
when (event) {
|
||||
MultiWalletFinalizeComponent.Event.OneBackupCardAdded -> {
|
||||
artworksState.value = WalletArtworksState.Leapfrog(
|
||||
threeCards = model.state.value.isThreeCards,
|
||||
step = WalletArtworksState.Leapfrog.Step.Second,
|
||||
)
|
||||
}
|
||||
MultiWalletFinalizeComponent.Event.TwoBackupCardsAdded -> {
|
||||
if (model.state.value.isThreeCards) {
|
||||
artworksState.value = WalletArtworksState.Leapfrog(
|
||||
threeCards = model.state.value.isThreeCards,
|
||||
step = WalletArtworksState.Leapfrog.Step.Third,
|
||||
)
|
||||
} else {
|
||||
handleNavigationEvent(Done)
|
||||
}
|
||||
}
|
||||
MultiWalletFinalizeComponent.Event.ThreeBackupCardsAdded -> {
|
||||
handleNavigationEvent(Done)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openAccessCodeBottomSheet() { bottomSheetNavigation.navigate { } }
|
||||
|
||||
@OptIn(FaultyDecomposeApi::class)
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
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
|
||||
import com.tangem.sdk.api.BackupServiceHolder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -21,6 +22,7 @@ private const val MINIMUM_ACCESS_CODE_LENGTH = 4
|
|||
internal class MultiWalletAccessCodeModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val backupServiceHolder: BackupServiceHolder,
|
||||
) : Model() {
|
||||
|
||||
private val _uiState = MutableStateFlow(getInitialState())
|
||||
|
|
@ -112,6 +114,10 @@ internal class MultiWalletAccessCodeModel @Inject constructor(
|
|||
}
|
||||
MultiWalletAccessCodeUM.Step.ConfirmAccessCode -> {
|
||||
if (checkAccessCode()) {
|
||||
backupServiceHolder.backupService.get()?.setAccessCode(_uiState.value.accessCodeFirst.text)
|
||||
|
||||
// TODO delete access code from state
|
||||
// make on done
|
||||
params.multiWalletState.update {
|
||||
it.copy(accessCode = OnboardingMultiWalletState.AccessCode(uiState.value.accessCodeFirst.text))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,6 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.tangem.common.card.Card
|
||||
|
||||
// TODO maybe delete some fields in the future
|
||||
data class BackupState(
|
||||
val primaryCardId: String? = null,
|
||||
val primaryCardBatchId: String? = null,
|
||||
val backupCardsNumber: Int = 0,
|
||||
val backupCards: List<Card> = emptyList(),
|
||||
val backupCardIds: List<CardId> = emptyList(),
|
||||
val backupCardBatchIds: List<CardId> = emptyList(),
|
||||
@Transient
|
||||
val backupCardsArtworks: Map<CardId, Bitmap> = 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()
|
||||
}
|
||||
)
|
||||
|
|
@ -67,7 +67,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
addBackupButtonEnabled = true,
|
||||
addBackupButtonLoading = false,
|
||||
onAddBackupClick = ::startBackupWallet,
|
||||
onFinalizeButtonClick = {},
|
||||
onFinalizeButtonClick = ::onFinalizeClick,
|
||||
onSkipButtonClick = {
|
||||
// eventFlow.tryEmit(Unit)
|
||||
},
|
||||
|
|
@ -80,7 +80,9 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun startBackupWallet() {
|
||||
backupService.discardSavedBackup()
|
||||
if (state.value.backupCardsNumber == 0) {
|
||||
backupService.discardSavedBackup()
|
||||
}
|
||||
val primaryCard = scanResponse.primaryCard
|
||||
|
||||
if (primaryCard != null) {
|
||||
|
|
@ -107,6 +109,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
eventFlow.emit(MultiWalletBackupComponent.Event.OneDeviceAdded)
|
||||
}
|
||||
params.multiWalletState.update { it.copy(isThreeCards = false) }
|
||||
st.copy(
|
||||
title = resourceReference(R.string.onboarding_title_one_backup_card),
|
||||
bodyText = resourceReference(R.string.onboarding_subtitle_one_backup_card),
|
||||
|
|
@ -118,6 +121,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
eventFlow.emit(MultiWalletBackupComponent.Event.TwoDeviceAdded)
|
||||
}
|
||||
params.multiWalletState.update { it.copy(isThreeCards = true) }
|
||||
st.copy(
|
||||
title = resourceReference(R.string.onboarding_title_two_backup_cards),
|
||||
bodyText = resourceReference(R.string.onboarding_subtitle_two_backup_cards),
|
||||
|
|
@ -130,6 +134,19 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun onFinalizeClick() {
|
||||
when (state.value.backupCardsNumber) {
|
||||
1 -> {
|
||||
// TODO show dialog
|
||||
params.multiWalletState.update { it.copy(isThreeCards = false) }
|
||||
}
|
||||
2 -> {
|
||||
params.multiWalletState.update { it.copy(isThreeCards = true) }
|
||||
}
|
||||
}
|
||||
modelScope.launch { eventFlow.emit(MultiWalletBackupComponent.Event.Done) }
|
||||
}
|
||||
|
||||
private fun addBackupCardWithService() {
|
||||
_uiState.update { st ->
|
||||
st.copy(addBackupButtonLoading = true)
|
||||
|
|
@ -147,7 +164,6 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
is CompletionResult.Success -> {
|
||||
state.update {
|
||||
it.copy(
|
||||
backupCards = it.backupCards + result.data,
|
||||
backupCardsNumber = it.backupCardsNumber + 1,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,45 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model.MultiWalletFinalizeModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.ui.MultiWalletFinalize
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class MultiWalletFinalizeComponent(
|
||||
context: AppComponentContext,
|
||||
params: MultiWalletChildParams,
|
||||
onNextStep: (OnboardingMultiWalletState.Step) -> Unit,
|
||||
backButtonClickFlow: SharedFlow<Unit>,
|
||||
onEvent: (Event) -> Unit,
|
||||
) : AppComponentContext by context, MultiWalletChildComponent {
|
||||
|
||||
private val model: MultiWalletFinalizeModel = getOrCreateModel(params)
|
||||
|
||||
init {
|
||||
componentScope.launch {
|
||||
model.onEvent.collect {
|
||||
onEvent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
MultiWalletFinalize(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
enum class Event {
|
||||
OneBackupCardAdded, TwoBackupCardsAdded, ThreeBackupCardsAdded
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model
|
||||
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import javax.inject.Inject
|
||||
|
||||
class BackupValidator @Inject constructor() {
|
||||
|
||||
fun isValidFull(cardDTO: CardDTO): Boolean {
|
||||
return validateBackupStatus(cardDTO) && validateCurves(cardDTO)
|
||||
}
|
||||
|
||||
fun isValidBackupStatus(cardDTO: CardDTO): Boolean {
|
||||
return validateBackupStatus(cardDTO)
|
||||
}
|
||||
|
||||
private fun validateCurves(cardDTO: CardDTO): Boolean {
|
||||
val config = CardConfig.createConfig(cardDTO)
|
||||
// / Since the curve `bls12381_G2_AUG` was added later into first generation of wallets,
|
||||
// we cannot determine whether this curve is missing due to an error or because the user
|
||||
// did not want to recreate the wallet.
|
||||
val expectedCurves = config.mandatoryCurves
|
||||
.filterNot { it == EllipticCurve.Bls12381G2Aug }
|
||||
val curves = cardDTO.wallets.map { it.curve }
|
||||
for (expectedCurve in expectedCurves) {
|
||||
val cardCurvesCount = curves.count { it == expectedCurve }
|
||||
|
||||
// missing curve
|
||||
if (cardCurvesCount == 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
// duplicated curve
|
||||
if (cardCurvesCount > 1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun validateBackupStatus(cardDTO: CardDTO): Boolean {
|
||||
val backupStatus = cardDTO.backupStatus
|
||||
backupStatus ?: return true // for card with null backup status, validation should always returns true
|
||||
return backupStatus !is CardDTO.BackupStatus.CardLinked
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
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.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.models.scan.isRing
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
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.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
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.resetCardDialog
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.sdk.api.BackupServiceHolder
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.StringsSigns
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@ComponentScoped
|
||||
internal class MultiWalletFinalizeModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val backupServiceHolder: BackupServiceHolder,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val getCardInfoUseCase: GetCardInfoUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val cardRepository: CardRepository,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<MultiWalletChildParams>()
|
||||
private val multiWalletState get() = params.multiWalletState
|
||||
private val _uiState = MutableStateFlow(
|
||||
MultiWalletFinalizeUM(
|
||||
isRing = backupServiceHolder.backupService.get()?.primaryCardBatchId?.let { isRing(it) } ?: false,
|
||||
onScanClick = ::onLinkClick,
|
||||
cardNumber = backupServiceHolder.backupService.get()?.primaryCardId?.lastMasked().orEmpty(),
|
||||
),
|
||||
)
|
||||
private val backupCardIds = backupServiceHolder.backupService.get()?.backupCardIds.orEmpty()
|
||||
private var walletHasBackupError = false
|
||||
|
||||
val uiState = _uiState.asStateFlow()
|
||||
val onEvent = MutableSharedFlow<MultiWalletFinalizeComponent.Event>()
|
||||
|
||||
private fun onLinkClick() {
|
||||
when (_uiState.value.step) {
|
||||
MultiWalletFinalizeUM.Step.Primary -> {
|
||||
writePrimaryCard()
|
||||
}
|
||||
MultiWalletFinalizeUM.Step.BackupDevice1 -> {
|
||||
writeBackupCard(cardIndex = 0)
|
||||
}
|
||||
MultiWalletFinalizeUM.Step.BackupDevice2 -> {
|
||||
writeBackupCard(cardIndex = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun writePrimaryCard() {
|
||||
val backupService = backupServiceHolder.backupService.get() ?: return
|
||||
// store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing))
|
||||
|
||||
val primaryCardBatchId = backupService.primaryCardBatchId ?: return
|
||||
val isRing = isRing(primaryCardBatchId)
|
||||
val iconScanRes = if (isRing) R.drawable.img_hand_scan_ring else null
|
||||
|
||||
tangemSdkManager.changeProductType(isRing)
|
||||
backupService.proceedBackup(iconScanRes = iconScanRes) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
modelScope.launch { onEvent.emit(MultiWalletFinalizeComponent.Event.OneBackupCardAdded) }
|
||||
_uiState.update { st ->
|
||||
st.copy(
|
||||
step = MultiWalletFinalizeUM.Step.BackupDevice1,
|
||||
isRing = backupService.backupCardsBatchIds.getOrNull(0)?.let { isRing(it) } ?: false,
|
||||
scanPrimary = false,
|
||||
cardNumber = backupService.backupCardIds.firstOrNull()?.lastMasked() ?: "",
|
||||
)
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> Unit
|
||||
}
|
||||
tangemSdkManager.clearProductType()
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeBackupCard(cardIndex: Int) {
|
||||
val backupService = backupServiceHolder.backupService.get() ?: return
|
||||
|
||||
// store.dispatchOnMain(BackupAction.SetHasRing(hasRing = isRing))
|
||||
|
||||
val backupCardBatchId = backupService.backupCardsBatchIds.getOrNull(cardIndex) ?: return
|
||||
val isRing = isRing(backupCardBatchId)
|
||||
val iconScanRes = if (isRing) R.drawable.img_hand_scan_ring else null
|
||||
|
||||
tangemSdkManager.changeProductType(isRing)
|
||||
backupService.proceedBackup(iconScanRes = iconScanRes) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
val backupValidator = BackupValidator()
|
||||
if (backupValidator.isValidBackupStatus(CardDTO(result.data)).not()) {
|
||||
// TODO store.dispatchOnMain(BackupAction.ErrorInBackupCard)
|
||||
walletHasBackupError = true
|
||||
}
|
||||
|
||||
if (backupService.currentState == BackupService.State.Finished) {
|
||||
finishBackup()
|
||||
} else {
|
||||
modelScope.launch { onEvent.emit(MultiWalletFinalizeComponent.Event.TwoBackupCardsAdded) }
|
||||
_uiState.update { st ->
|
||||
st.copy(
|
||||
step = MultiWalletFinalizeUM.Step.BackupDevice2,
|
||||
isRing = backupService.backupCardsBatchIds
|
||||
.getOrNull(cardIndex + 1)?.let { isRing(it) } ?: false,
|
||||
cardNumber = backupService.backupCardIds.getOrNull(cardIndex + 1)
|
||||
?.lastMasked() ?: "",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
if (result.error is TangemSdkError.WalletAlreadyCreated) {
|
||||
// show should reset dialog
|
||||
handleActivationError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tangemSdkManager.clearProductType()
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishBackup() {
|
||||
// TODO Analytics.send(Onboarding.Backup.Finished(backupState.backupCardsNumber))
|
||||
|
||||
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)
|
||||
|
||||
// save user wallet for manage tokens screen
|
||||
params.multiWalletState.update {
|
||||
it.copy(resultUserWallet = userWallet)
|
||||
}
|
||||
|
||||
onEvent.emit(MultiWalletFinalizeComponent.Event.ThreeBackupCardsAdded)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createUserWallet(scanResponse: ScanResponse): UserWallet {
|
||||
return requireNotNull(
|
||||
value = UserWalletBuilder(scanResponse, generateWalletNameUseCase)
|
||||
.backupCardsIds(backupCardIds.toSet())
|
||||
.hasBackupError(walletHasBackupError)
|
||||
.build(),
|
||||
lazyMessage = { "User wallet not created" },
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun ScanResponse.updateScanResponseAfterBackup(): ScanResponse {
|
||||
val cardsCount = if (params.multiWalletState.value.isThreeCards) 3 else 2
|
||||
|
||||
val card = card.copy(
|
||||
backupStatus = CardDTO.BackupStatus.Active(cardCount = cardsCount),
|
||||
isAccessCodeSet = true,
|
||||
)
|
||||
return copy(card = card)
|
||||
}
|
||||
|
||||
private fun handleActivationError() {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
dialog = resetCardDialog(
|
||||
onConfirm = ::navigateToSupportScreen,
|
||||
dismiss = { _uiState.update { it.copy(dialog = null) } },
|
||||
onDismissButtonClick = ::resetCard,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetCard() {
|
||||
val scanResponse = params.parentParams.scanResponse
|
||||
|
||||
modelScope.launch {
|
||||
tangemSdkManager.resetToFactorySettings(
|
||||
cardId = scanResponse.card.cardId,
|
||||
allowsRequestAccessCodeFromRepository = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToSupportScreen() {
|
||||
modelScope.launch {
|
||||
val cardInfo = getCardInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch
|
||||
sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo))
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.lastMasked(): String {
|
||||
val space = StringsSigns.NON_BREAKING_SPACE
|
||||
fun String.splitBySpace() = reversed().chunked(size = 4).joinToString(separator = "$space").reversed()
|
||||
val last4 = takeLast(n = 4).splitBySpace()
|
||||
val mask = "$space*$space*$space*$space"
|
||||
return mask + last4
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.state
|
||||
|
||||
data class MultiWalletFinalizeUM(
|
||||
val step: Step = Step.Device1,
|
||||
val cardNumber: String = "",
|
||||
) {
|
||||
enum class Step {
|
||||
Device1, Device2, Device3
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,86 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.state.MultiWalletFinalizeUM
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.ui.state.MultiWalletFinalizeUM
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@Composable
|
||||
fun MultiWalletFinalize(state: MultiWalletFinalizeUM, modifier: Modifier = Modifier) {
|
||||
internal fun MultiWalletFinalize(state: MultiWalletFinalizeUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
verticalArrangement = Arrangement.Bottom,
|
||||
) {
|
||||
// TODO
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 32.dp, end = 32.dp, bottom = 74.dp)
|
||||
.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
text = stringResource(
|
||||
when {
|
||||
state.scanPrimary && state.isRing -> R.string.common_origin_ring
|
||||
state.scanPrimary && state.isRing.not() -> R.string.common_origin_card
|
||||
state.scanPrimary.not() && state.isRing -> R.string.onboarding_title_backup_ring
|
||||
else -> R.string.onboarding_title_backup_card
|
||||
},
|
||||
),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.h2,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 12.dp),
|
||||
text = if (state.isRing) {
|
||||
stringResource(R.string.onboarding_subtitle_scan_ring)
|
||||
} else {
|
||||
stringResource(
|
||||
R.string.onboarding_subtitle_scan_backup_card_format,
|
||||
state.cardNumber,
|
||||
)
|
||||
},
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.body1,
|
||||
)
|
||||
}
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(
|
||||
if (state.isRing) R.string.onboarding_button_backup_ring else R.string.onboarding_button_backup_origin,
|
||||
),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
onClick = state.onScanClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TangemThemePreview {
|
||||
MultiWalletFinalize(
|
||||
state = MultiWalletFinalizeUM(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.ui.state
|
||||
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.OnboardingDialogUM
|
||||
|
||||
internal data class MultiWalletFinalizeUM(
|
||||
val step: Step = Step.Primary,
|
||||
val isRing: Boolean = false,
|
||||
val scanPrimary: Boolean = true,
|
||||
val cardNumber: String = "",
|
||||
val onScanClick: () -> Unit = {},
|
||||
val dialog: OnboardingDialogUM? = null,
|
||||
) {
|
||||
enum class Step {
|
||||
Primary, BackupDevice1, BackupDevice2
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.DefaultOnboardingMulti
|
|||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.model.MultiWalletAccessCodeModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model.MultiWalletBackupModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.model.MultiWalletCreateWalletModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model.MultiWalletFinalizeModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.MultiWalletSeedPhraseModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel
|
||||
import dagger.Binds
|
||||
|
|
@ -54,4 +55,9 @@ internal interface ModelModule {
|
|||
@IntoMap
|
||||
@ClassKey(MultiWalletAccessCodeModel::class)
|
||||
fun provideModel5(model: MultiWalletAccessCodeModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(MultiWalletFinalizeModel::class)
|
||||
fun provideModel6(model: MultiWalletFinalizeModel): Model
|
||||
}
|
||||
|
|
@ -26,6 +26,8 @@ internal class OnboardingMultiWalletModel @Inject constructor(
|
|||
currentStep = getInitialStep(),
|
||||
currentScanResponse = params.scanResponse,
|
||||
accessCode = null,
|
||||
isThreeCards = true,
|
||||
resultUserWallet = null,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.model
|
||||
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
||||
data class OnboardingMultiWalletState(
|
||||
val currentStep: Step,
|
||||
val accessCode: AccessCode?,
|
||||
val isThreeCards: Boolean,
|
||||
val currentScanResponse: ScanResponse,
|
||||
val resultUserWallet: UserWallet?, // TODO make callback instead
|
||||
) {
|
||||
/**
|
||||
* Wallet1
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@ fun screenTitleByStep(step: OnboardingMultiWalletState.Step): TextReference = wh
|
|||
OnboardingMultiWalletState.Step.AddBackupDevice ->
|
||||
resourceReference(R.string.onboarding_navbar_title_creating_backup)
|
||||
OnboardingMultiWalletState.Step.Finalize -> TODO()
|
||||
OnboardingMultiWalletState.Step.Done -> TODO()
|
||||
OnboardingMultiWalletState.Step.Done -> error("No title for Done step")
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ internal class DefaultOnboardingStepperComponent @AssistedInject constructor(
|
|||
init {
|
||||
componentScope.launch {
|
||||
state.collect {
|
||||
// TODO
|
||||
Timber.tag("ASDASD").d("State: $it")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue