Updated on 2026-08-14
This commit is contained in:
parent
aa6ddb9428
commit
9597f49fed
18 changed files with 556 additions and 97 deletions
|
|
@ -105,6 +105,14 @@ internal class DefaultOnboardingEntryComponent @AssistedInject constructor(
|
|||
}.saveIn(innerNavigationLinkJobHolder)
|
||||
}
|
||||
}
|
||||
|
||||
componentScope.launch {
|
||||
model.titleProvider.currentTitle.collect { title ->
|
||||
stepperComponent.state.update {
|
||||
it.copy(title = title)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -3,14 +3,24 @@ package com.tangem.features.onboarding.v2.multiwallet.impl
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
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.extensions.compose.jetpack.subscribeAsState
|
||||
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.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.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.backup.MultiWalletBackupComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.MultiWalletCreateWalletComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.ui.OnboardingMultiWallet
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -23,24 +33,74 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
|
||||
private val model: OnboardingMultiWalletModel = getOrCreateModel(params)
|
||||
|
||||
private val stackNavigation = StackNavigation<OnboardingMultiWalletState.Step>()
|
||||
|
||||
override val innerNavigation: InnerNavigation = object : InnerNavigation {
|
||||
override val state = MutableStateFlow(
|
||||
Wallet12InnerNavigationState(1, 5), // TODO
|
||||
Wallet12InnerNavigationState(1, 5),
|
||||
)
|
||||
|
||||
override fun pop(onComplete: (Boolean) -> Unit) {
|
||||
// TODO
|
||||
// TODO add warning dialog
|
||||
stackNavigation.pop(onComplete)
|
||||
}
|
||||
}
|
||||
|
||||
private val childStack: Value<ChildStack<OnboardingMultiWalletState.Step, MultiWalletChildComponent>> = childStack(
|
||||
key = "innerStack",
|
||||
source = stackNavigation,
|
||||
serializer = null,
|
||||
initialConfiguration = model.state.value.currentStep,
|
||||
handleBackButton = true,
|
||||
childFactory = { configuration, factoryContext -> createChild(configuration, childByContext(factoryContext)) },
|
||||
)
|
||||
|
||||
private fun createChild(
|
||||
step: OnboardingMultiWalletState.Step,
|
||||
childContext: AppComponentContext,
|
||||
): MultiWalletChildComponent {
|
||||
return when (step) {
|
||||
OnboardingMultiWalletState.Step.CreateWallet -> MultiWalletCreateWalletComponent(
|
||||
context = childContext,
|
||||
params = MultiWalletChildParams(
|
||||
multiWalletState = model.state,
|
||||
parentParams = params,
|
||||
),
|
||||
onDone = ::onStepDone,
|
||||
)
|
||||
OnboardingMultiWalletState.Step.AddBackupDevice -> MultiWalletBackupComponent(
|
||||
context = childContext,
|
||||
params = MultiWalletChildParams(
|
||||
multiWalletState = model.state,
|
||||
parentParams = params,
|
||||
),
|
||||
onDone = ::onStepDone,
|
||||
)
|
||||
OnboardingMultiWalletState.Step.FinishBackup -> TODO()
|
||||
OnboardingMultiWalletState.Step.Done -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onStepDone() {
|
||||
when (model.state.value.currentStep) {
|
||||
OnboardingMultiWalletState.Step.CreateWallet ->
|
||||
stackNavigation.push(OnboardingMultiWalletState.Step.AddBackupDevice)
|
||||
OnboardingMultiWalletState.Step.AddBackupDevice -> TODO()
|
||||
OnboardingMultiWalletState.Step.FinishBackup -> TODO()
|
||||
OnboardingMultiWalletState.Step.Done -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val uiState by model.uiState.collectAsStateWithLifecycle()
|
||||
val stackState by childStack.subscribeAsState()
|
||||
|
||||
OnboardingMultiWallet(
|
||||
modifier = modifier,
|
||||
state = uiState,
|
||||
)
|
||||
Children(
|
||||
stack = stackState,
|
||||
animation = stackAnimation(slide()),
|
||||
) {
|
||||
it.instance.Content(Modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child
|
||||
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface MultiWalletChildComponent : ComposableContentComponent
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child
|
||||
|
||||
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class MultiWalletChildParams(
|
||||
val multiWalletState: MutableStateFlow<OnboardingMultiWalletState>,
|
||||
val parentParams: OnboardingMultiWalletComponent.Params,
|
||||
)
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup
|
||||
|
||||
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.core.ui.extensions.resourceReference
|
||||
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.MultiWalletChildComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model.MultiWalletBackupModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.MultiWalletBackup
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
class MultiWalletBackupComponent(
|
||||
context: AppComponentContext,
|
||||
params: MultiWalletChildParams,
|
||||
onDone: () -> Unit,
|
||||
) : AppComponentContext by context, MultiWalletChildComponent {
|
||||
|
||||
private val model: MultiWalletBackupModel = getOrCreateModel(params)
|
||||
|
||||
init {
|
||||
params.parentParams.titleProvider.changeTitle(
|
||||
text = resourceReference(R.string.onboarding_navbar_title_creating_backup),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
MultiWalletBackup(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model
|
||||
|
||||
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.child.MultiWalletChildParams
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state.MultiWalletBackupUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@ComponentScoped
|
||||
class MultiWalletBackupModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private val params = paramsContainer.require<MultiWalletChildParams>()
|
||||
|
||||
private val _uiState = MutableStateFlow(
|
||||
MultiWalletBackupUM(
|
||||
finalizeButtonEnabled = false,
|
||||
onAddBackupClick = {},
|
||||
onFinalizeButtonClick = {},
|
||||
),
|
||||
)
|
||||
|
||||
val uiState: StateFlow<MultiWalletBackupUM> = _uiState
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.components.SecondaryButton
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state.MultiWalletBackupUM
|
||||
|
||||
@Composable
|
||||
fun MultiWalletBackup(state: MultiWalletBackupUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(100.dp)
|
||||
.background(Color.Black),
|
||||
)
|
||||
}
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
text = stringResource(R.string.onboarding_button_add_backup_card),
|
||||
onClick = state.onAddBackupClick,
|
||||
)
|
||||
|
||||
SecondaryButton(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
enabled = state.finalizeButtonEnabled,
|
||||
text = stringResource(R.string.onboarding_button_finalize_backup),
|
||||
onClick = state.onFinalizeButtonClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TangemThemePreview {
|
||||
MultiWalletBackup(
|
||||
state = MultiWalletBackupUM(
|
||||
finalizeButtonEnabled = true,
|
||||
onAddBackupClick = {},
|
||||
onFinalizeButtonClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state
|
||||
|
||||
data class MultiWalletBackupUM(
|
||||
val finalizeButtonEnabled: Boolean,
|
||||
val onAddBackupClick: () -> Unit,
|
||||
val onFinalizeButtonClick: () -> Unit,
|
||||
)
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet
|
||||
|
||||
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.core.ui.extensions.resourceReference
|
||||
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.MultiWalletChildComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.model.MultiWalletCreateWalletModel
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.MultiWalletCreateWallet
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MultiWalletCreateWalletComponent(
|
||||
context: AppComponentContext,
|
||||
params: MultiWalletChildParams,
|
||||
onDone: () -> Unit,
|
||||
) : AppComponentContext by context, MultiWalletChildComponent {
|
||||
|
||||
private val model: MultiWalletCreateWalletModel = getOrCreateModel(params)
|
||||
|
||||
init {
|
||||
params.parentParams.titleProvider.changeTitle(
|
||||
text = resourceReference(R.string.onboarding_create_wallet_header),
|
||||
)
|
||||
|
||||
componentScope.launch {
|
||||
model.onDone.collect { onDone() }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
MultiWalletCreateWallet(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.model
|
||||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.state.MultiWalletCreateWalletUM
|
||||
|
||||
internal fun resetCardDialog(onConfirm: () -> Unit, onDismiss: () -> Unit, onDismissButtonClick: () -> Unit) =
|
||||
MultiWalletCreateWalletUM.Dialog(
|
||||
title = resourceReference(R.string.onboarding_activation_error_title),
|
||||
description = resourceReference(R.string.onboarding_activation_error_message),
|
||||
confirmButtonText = resourceReference(R.string.common_ok),
|
||||
dismissButtonText = resourceReference(R.string.common_support),
|
||||
onDismiss = onDismiss,
|
||||
onConfirm = onConfirm,
|
||||
onDismissButtonClick = onDismissButtonClick,
|
||||
)
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.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.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
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.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ComponentScoped
|
||||
class MultiWalletCreateWalletModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val getCardInfoUseCase: GetCardInfoUseCase,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<MultiWalletChildParams>()
|
||||
private val multiWalletState
|
||||
get() = params.multiWalletState
|
||||
|
||||
private val _uiState = MutableStateFlow(
|
||||
MultiWalletCreateWalletUM(
|
||||
onCreateWalletClick = { createWallet(false) },
|
||||
showSeedPhraseOption = params.parentParams.withSeedPhraseFlow,
|
||||
onOtherOptionsClick = { /* navigate */ },
|
||||
dialog = null,
|
||||
),
|
||||
)
|
||||
|
||||
val uiState: StateFlow<MultiWalletCreateWalletUM> = _uiState
|
||||
val onDone = MutableSharedFlow<Unit>()
|
||||
|
||||
private fun createWallet(shouldReset: Boolean) {
|
||||
modelScope.launch {
|
||||
val result = tangemSdkManager.createProductWallet(
|
||||
scanResponse = multiWalletState.value.currentScanResponse,
|
||||
shouldReset = shouldReset,
|
||||
)
|
||||
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
multiWalletState.update {
|
||||
it.copy(
|
||||
currentScanResponse = it.currentScanResponse.copy(
|
||||
card = result.data.card,
|
||||
derivedKeys = result.data.derivedKeys,
|
||||
primaryCard = result.data.primaryCard,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
onDone.emit(Unit)
|
||||
// TODO
|
||||
// Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully())
|
||||
}
|
||||
|
||||
is CompletionResult.Failure -> {
|
||||
if (result.error is TangemSdkError.WalletAlreadyCreated) {
|
||||
// show should reset dialog
|
||||
handleActivationError()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleActivationError() {
|
||||
_uiState.update { state ->
|
||||
state.copy(
|
||||
dialog = resetCardDialog(
|
||||
onConfirm = {
|
||||
_uiState.update { it.copy(dialog = null) }
|
||||
resetCard()
|
||||
},
|
||||
onDismiss = {
|
||||
_uiState.update { it.copy(dialog = null) }
|
||||
},
|
||||
onDismissButtonClick = ::navigateToSupportScreen,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetCard() {
|
||||
createWallet(true)
|
||||
}
|
||||
|
||||
fun navigateToSupportScreen() {
|
||||
modelScope.launch {
|
||||
val cardInfo = getCardInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch
|
||||
sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.components.PrimaryButtonIconEnd
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.state.MultiWalletCreateWalletUM
|
||||
|
||||
@Composable
|
||||
fun MultiWalletCreateWallet(state: MultiWalletCreateWalletUM, modifier: Modifier = Modifier) {
|
||||
if (state.dialog != null) {
|
||||
BasicDialog(
|
||||
title = state.dialog.title.resolveReference(),
|
||||
message = state.dialog.description.resolveReference(),
|
||||
confirmButton = DialogButtonUM(
|
||||
title = state.dialog.confirmButtonText.resolveReference(),
|
||||
onClick = state.dialog.onConfirm,
|
||||
),
|
||||
dismissButton = DialogButtonUM(
|
||||
title = state.dialog.dismissButtonText.resolveReference(),
|
||||
onClick = state.dialog.onDismissButtonClick,
|
||||
),
|
||||
onDismissDialog = state.dialog.onDismiss,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(100.dp)
|
||||
.background(Color.Black),
|
||||
)
|
||||
}
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
text = stringResource(R.string.onboarding_create_wallet_button_create_wallet),
|
||||
onClick = state.onCreateWalletClick,
|
||||
)
|
||||
|
||||
SecondaryButton(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.onboarding_create_wallet_options_button_options),
|
||||
onClick = state.onOtherOptionsClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TangemThemePreview {
|
||||
MultiWalletCreateWallet(
|
||||
state = MultiWalletCreateWalletUM(
|
||||
onCreateWalletClick = {},
|
||||
showSeedPhraseOption = true,
|
||||
onOtherOptionsClick = {},
|
||||
dialog = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.state
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
data class MultiWalletCreateWalletUM(
|
||||
val onCreateWalletClick: () -> Unit,
|
||||
val showSeedPhraseOption: Boolean,
|
||||
val onOtherOptionsClick: () -> Unit,
|
||||
val dialog: Dialog?,
|
||||
) {
|
||||
data class Dialog(
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
val dismissButtonText: TextReference,
|
||||
val confirmButtonText: TextReference,
|
||||
val onConfirm: () -> Unit,
|
||||
val onDismissButtonClick: () -> Unit,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -4,6 +4,8 @@ import com.tangem.core.decompose.di.DecomposeComponent
|
|||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.DefaultOnboardingMultiWalletComponent
|
||||
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.model.OnboardingMultiWalletModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
|
@ -30,4 +32,14 @@ internal interface ModelModule {
|
|||
@IntoMap
|
||||
@ClassKey(OnboardingMultiWalletModel::class)
|
||||
fun provideModel(model: OnboardingMultiWalletModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(MultiWalletBackupModel::class)
|
||||
fun provideModel2(model: MultiWalletBackupModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(MultiWalletCreateWalletModel::class)
|
||||
fun provideModel3(model: MultiWalletCreateWalletModel): Model
|
||||
}
|
||||
|
|
@ -1,22 +1,14 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.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.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.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.ui.state.OnboardingMultiWalletUM
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -24,27 +16,14 @@ import javax.inject.Inject
|
|||
internal class OnboardingMultiWalletModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val getCardInfoUseCase: GetCardInfoUseCase,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<OnboardingMultiWalletComponent.Params>()
|
||||
private val currentScanResponse = MutableStateFlow(params.scanResponse)
|
||||
|
||||
val state = MutableStateFlow(
|
||||
OnboardingMultiWalletState(
|
||||
currentStep = getInitialStep(),
|
||||
),
|
||||
)
|
||||
|
||||
val uiState = MutableStateFlow(
|
||||
OnboardingMultiWalletUM(
|
||||
onCreateWalletClick = { createWallet(false) },
|
||||
showSeedPhraseOption = params.withSeedPhraseFlow,
|
||||
onOtherOptionsClick = { /* navigate */ },
|
||||
onBack = { },
|
||||
dialog = null,
|
||||
currentScanResponse = params.scanResponse,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -53,7 +32,7 @@ internal class OnboardingMultiWalletModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getInitialStep(): OnboardingMultiWalletState.Step {
|
||||
val card = currentScanResponse.value.card
|
||||
val card = params.scanResponse.card
|
||||
|
||||
return when {
|
||||
card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup ->
|
||||
|
|
@ -78,63 +57,4 @@ internal class OnboardingMultiWalletModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWallet(shouldReset: Boolean) {
|
||||
modelScope.launch {
|
||||
val result = tangemSdkManager.createProductWallet(
|
||||
scanResponse = currentScanResponse.value,
|
||||
shouldReset = shouldReset,
|
||||
)
|
||||
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
currentScanResponse.update {
|
||||
it.copy(
|
||||
card = result.data.card,
|
||||
derivedKeys = result.data.derivedKeys,
|
||||
primaryCard = result.data.primaryCard,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully())
|
||||
}
|
||||
|
||||
is CompletionResult.Failure -> {
|
||||
if (result.error is TangemSdkError.WalletAlreadyCreated) {
|
||||
// show should reset dialog
|
||||
handleActivationError()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleActivationError() {
|
||||
uiState.update {
|
||||
it.copy(
|
||||
dialog = resetCardDialog(
|
||||
onConfirm = {
|
||||
uiState.update { it.copy(dialog = null) }
|
||||
resetCard()
|
||||
},
|
||||
onDismiss = {
|
||||
uiState.update { it.copy(dialog = null) }
|
||||
},
|
||||
onDismissButtonClick = ::navigateToSupportScreen,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetCard() {
|
||||
createWallet(true)
|
||||
}
|
||||
|
||||
fun navigateToSupportScreen() {
|
||||
modelScope.launch {
|
||||
val cardInfo = getCardInfoUseCase(currentScanResponse.value).getOrNull() ?: return@launch
|
||||
sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.model
|
||||
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
||||
data class OnboardingMultiWalletState(
|
||||
val currentStep: Step,
|
||||
val currentScanResponse: ScanResponse,
|
||||
) {
|
||||
|
||||
enum class Step {
|
||||
GeneratePrivateKeys, CreateWallet, AddBackupDevice, FinishBackup, Done
|
||||
CreateWallet, AddBackupDevice, FinishBackup, Done
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,10 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.features.onboarding.v2.impl.R
|
||||
|
||||
fun screenTitleByStep(step: OnboardingMultiWalletState.Step): TextReference = when (step) {
|
||||
OnboardingMultiWalletState.Step.GeneratePrivateKeys -> TODO()
|
||||
OnboardingMultiWalletState.Step.CreateWallet -> resourceReference(R.string.onboarding_create_wallet_header)
|
||||
OnboardingMultiWalletState.Step.AddBackupDevice -> TODO()
|
||||
OnboardingMultiWalletState.Step.CreateWallet ->
|
||||
resourceReference(R.string.onboarding_create_wallet_header)
|
||||
OnboardingMultiWalletState.Step.AddBackupDevice ->
|
||||
resourceReference(R.string.onboarding_navbar_title_creating_backup)
|
||||
OnboardingMultiWalletState.Step.FinishBackup -> TODO()
|
||||
OnboardingMultiWalletState.Step.Done -> TODO()
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultOnboardingStepperComponent @AssistedInject constructor(
|
||||
@Assisted val context: AppComponentContext,
|
||||
|
|
@ -27,6 +28,14 @@ internal class DefaultOnboardingStepperComponent @AssistedInject constructor(
|
|||
|
||||
override val state = instanceKeeper.getOrCreateSimple { MutableStateFlow(params.initState) }
|
||||
|
||||
init {
|
||||
componentScope.launch {
|
||||
state.collect {
|
||||
Timber.tag("ASDASD").d("State: $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openSupport() {
|
||||
componentScope.launch {
|
||||
val cardInfo = getCardInfoUseCase(params.scanResponse).getOrNull() ?: return@launch
|
||||
|
|
@ -36,10 +45,10 @@ internal class DefaultOnboardingStepperComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by state.collectAsStateWithLifecycle()
|
||||
val uiState by state.collectAsStateWithLifecycle()
|
||||
|
||||
OnboardingStepper(
|
||||
state = state,
|
||||
state = uiState,
|
||||
onBackClick = remember(this) { params.popBack },
|
||||
onSupportButtonClick = remember(this) { ::openSupport },
|
||||
modifier = modifier,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue