diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt index ac06b7c4a5..623f315db0 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt @@ -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 diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt index 8cc7a9e553..8fbb204794 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt @@ -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() + 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( + 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 diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/MultiWalletChildComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/MultiWalletChildComponent.kt new file mode 100644 index 0000000000..c484f28a70 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/MultiWalletChildComponent.kt @@ -0,0 +1,5 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child + +import com.tangem.core.ui.decompose.ComposableContentComponent + +interface MultiWalletChildComponent : ComposableContentComponent \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/MultiWalletChildParams.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/MultiWalletChildParams.kt new file mode 100644 index 0000000000..3e2d3bffb3 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/MultiWalletChildParams.kt @@ -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, + val parentParams: OnboardingMultiWalletComponent.Params, +) \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/MultiWalletBackupComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/MultiWalletBackupComponent.kt new file mode 100644 index 0000000000..ff0422eeab --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/MultiWalletBackupComponent.kt @@ -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, + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt new file mode 100644 index 0000000000..1b6ddac97b --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt @@ -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() + + private val _uiState = MutableStateFlow( + MultiWalletBackupUM( + finalizeButtonEnabled = false, + onAddBackupClick = {}, + onFinalizeButtonClick = {}, + ), + ) + + val uiState: StateFlow = _uiState +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/ui/MultiWalletBackup.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/ui/MultiWalletBackup.kt new file mode 100644 index 0000000000..d050a2128f --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/ui/MultiWalletBackup.kt @@ -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 = {}, + ), + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/ui/state/MultiWalletBackupUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/ui/state/MultiWalletBackupUM.kt new file mode 100644 index 0000000000..013235cb7b --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/ui/state/MultiWalletBackupUM.kt @@ -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, +) \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/MultiWalletCreateWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/MultiWalletCreateWalletComponent.kt new file mode 100644 index 0000000000..713eb54a50 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/MultiWalletCreateWalletComponent.kt @@ -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, + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/Dialogs.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/Dialogs.kt new file mode 100644 index 0000000000..4dcd0f1696 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/Dialogs.kt @@ -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, + ) \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt new file mode 100644 index 0000000000..0a1992053f --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt @@ -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() + 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 = _uiState + val onDone = MutableSharedFlow() + + 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)) + } + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/ui/MultiWalletCreateWallet.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/ui/MultiWalletCreateWallet.kt new file mode 100644 index 0000000000..6b683f4ce6 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/ui/MultiWalletCreateWallet.kt @@ -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, + ), + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/ui/state/MultiWalletCreateWalletUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/ui/state/MultiWalletCreateWalletUM.kt new file mode 100644 index 0000000000..9c48ec07a2 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/ui/state/MultiWalletCreateWalletUM.kt @@ -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, + ) +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt index 1c7fd39182..363655f367 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt @@ -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 } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt index f031b2a3f6..2510f246f6 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt @@ -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() - 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)) - } - } } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt index d1b11653dd..b3c6b709c2 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletState.kt @@ -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 } } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt index fb735811de..73573ab2a6 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt @@ -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() } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/DefaultOnboardingStepperComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/DefaultOnboardingStepperComponent.kt index 2f4253b9f6..0689f4cb86 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/DefaultOnboardingStepperComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/DefaultOnboardingStepperComponent.kt @@ -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,