Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AND-9372 Onboarding: on old cards you can create a wallet with backup #3918

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ object OnboardingHelper {
fun whereToNavigate(scanResponse: ScanResponse): AppRoute {
val newOnboardingSupportTypes = scanResponse.productType == ProductType.Wallet2 ||
scanResponse.productType == ProductType.Ring ||
scanResponse.productType == ProductType.Wallet
scanResponse.productType == ProductType.Wallet // AppRoute.OnboardingOther is also supported
if (store.inject(DaggerGraphState::onboardingV2FeatureToggles).isOnboardingV2Enabled &&
newOnboardingSupportTypes
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,14 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
)

val backButtonClickFlow = MutableSharedFlow<Unit>()

override val innerNavigation: InnerNavigation = object : InnerNavigation {
override val state = innerNavigationStateFlow

override fun pop(onComplete: (Boolean) -> Unit) {
if (childStack.active.configuration == SeedPhrase) {
val config = childStack.active.configuration

if (config == SeedPhrase || config == Finalize) {
componentScope.launch { backButtonClickFlow.emit(Unit) }
} else {
model.onBack()
Expand Down Expand Up @@ -160,6 +163,8 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
Finalize -> MultiWalletFinalizeComponent(
context = childContext,
params = childParams,
backButtonClickFlow = backButtonClickFlow,
onBack = { model.onBack() },
onEvent = ::handleFinalizeComponentEvent,
)
Done -> error("Unexpected Done state")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ 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.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.model.MultiWalletBackupModel
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.MultiWalletBackup
import kotlinx.coroutines.flow.update
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Wallet1ChooseOptionComponent(
}

params.parentParams.titleProvider.changeTitle(
text = resourceReference(R.string.onboarding_create_wallet_header),
text = resourceReference(R.string.onboarding_getting_started),
)

componentScope.launch {
Expand All @@ -45,6 +45,7 @@ class Wallet1ChooseOptionComponent(
@Composable
override fun Content(modifier: Modifier) {
Wallet1ChooseOption(
canSkipBackup = model.canSkipBackup,
onBackupClick = {
onNextStep(OnboardingMultiWalletState.Step.AddBackupDevice)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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.common.TapWorkarounds.canSkipBackup
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletBuilder
import com.tangem.domain.wallets.models.UserWallet
Expand Down Expand Up @@ -36,6 +37,8 @@ internal class Wallet1ChooseOptionModel @Inject constructor(
analyticsHandler.send(OnboardingEvent.Backup.ScreenOpened)
}

val canSkipBackup = params.multiWalletState.value.currentScanResponse.card.canSkipBackup

fun onSkipClick() {
if (skipClicked) return
skipClicked = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R

@Composable
fun Wallet1ChooseOption(onSkipClick: () -> Unit, onBackupClick: () -> Unit, modifier: Modifier = Modifier) {
fun Wallet1ChooseOption(
canSkipBackup: Boolean,
onSkipClick: () -> Unit,
onBackupClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize()
Expand All @@ -34,37 +41,51 @@ fun Wallet1ChooseOption(onSkipClick: () -> Unit, onBackupClick: () -> Unit, modi
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResourceSafe(R.string.onboarding_create_wallet_header),
text = stringResourceSafe(R.string.onboarding_wallet_info_title_first),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 16.dp),
)

Text(
text = stringResourceSafe(R.string.onboarding_create_wallet_body),
text = stringResourceSafe(R.string.onboarding_wallet_info_subtitle_first),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 12.dp),
)
}

PrimaryButtonIconEnd(
PrimaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
.fillMaxWidth(),
iconResId = R.drawable.ic_tangem_24,
text = stringResourceSafe(R.string.onboarding_button_backup_now),
onClick = onBackupClick,
)

SecondaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResourceSafe(R.string.onboarding_button_skip_backup),
onClick = onSkipClick,
if (canSkipBackup) {
SecondaryButton(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
.fillMaxWidth(),
text = stringResourceSafe(R.string.onboarding_button_skip_backup),
onClick = onSkipClick,
)
}
}
}

@Preview(showBackground = true)
@Composable
private fun Preview() {
TangemThemePreview {
Wallet1ChooseOption(
canSkipBackup = true,
onSkipClick = {},
onBackupClick = {},
modifier = Modifier.fillMaxSize(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ 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.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletBuilder
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.state.MultiWalletCreateWalletUM
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.resetCardDialog
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState.Step
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -36,6 +41,8 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
private val getCardInfoUseCase: GetCardInfoUseCase,
private val cardRepository: CardRepository,
private val analyticsHandler: AnalyticsEventHandler,
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
private val saveWalletUseCase: SaveWalletUseCase,
) : Model() {

private val params = paramsContainer.require<MultiWalletChildParams>()
Expand All @@ -61,15 +68,15 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
showOtherOptionsButton = params.parentParams.withSeedPhraseFlow,
onOtherOptionsClick = {
modelScope.launch {
onDone.emit(OnboardingMultiWalletState.Step.SeedPhrase)
onDone.emit(Step.SeedPhrase)
}
},
dialog = null,
),
)

val uiState: StateFlow<MultiWalletCreateWalletUM> = _uiState
val onDone = MutableSharedFlow<OnboardingMultiWalletState.Step>()
val onDone = MutableSharedFlow<Step>()

init {
analyticsHandler.send(OnboardingEvent.CreateWallet.ScreenOpened)
Expand All @@ -96,13 +103,14 @@ internal class MultiWalletCreateWalletModel @Inject constructor(

cardRepository.startCardActivation(cardId = result.data.card.cardId)

if (params.parentParams.withSeedPhraseFlow) {
onDone.emit(OnboardingMultiWalletState.Step.AddBackupDevice)
} else {
onDone.emit(OnboardingMultiWalletState.Step.ChooseBackupOption)
}

analyticsHandler.send(OnboardingEvent.CreateWallet.WalletCreatedSuccessfully())

val cardDoesNotSupportBackup = result.data.card.settings.isBackupAllowed.not()
when {
cardDoesNotSupportBackup -> createWalletAndNavigateBackWithDone()
params.parentParams.withSeedPhraseFlow -> onDone.emit(Step.AddBackupDevice)
else -> onDone.emit(Step.ChooseBackupOption)
}
}

is CompletionResult.Failure -> {
Expand All @@ -115,6 +123,32 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
}
}

private fun createWalletAndNavigateBackWithDone() {
modelScope.launch {
val scanResponse = params.multiWalletState.value.currentScanResponse

val userWallet = createUserWallet(scanResponse)
saveWalletUseCase(userWallet, canOverride = true)
.onRight {
cardRepository.finishCardActivation(scanResponse.card.cardId)

// save user wallet for manage tokens screen
params.multiWalletState.update {
it.copy(resultUserWallet = userWallet)
}

onDone.emit(Step.Done)
}
}
}

private suspend fun createUserWallet(scanResponse: ScanResponse): UserWallet {
return requireNotNull(
value = UserWalletBuilder(scanResponse, generateWalletNameUseCase).build(),
lazyMessage = { "User wallet not created" },
)
}

private fun handleActivationError() {
_uiState.update { state ->
state.copy(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize

import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
Expand All @@ -12,13 +13,16 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChild
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
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.flow.SharedFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

@Suppress("UnusedPrivateMember")
internal class MultiWalletFinalizeComponent(
context: AppComponentContext,
params: MultiWalletChildParams,
backButtonClickFlow: SharedFlow<Unit>,
onBack: () -> Unit,
onEvent: (Event) -> Unit,
) : AppComponentContext by context, MultiWalletChildComponent {

Expand All @@ -40,12 +44,21 @@ internal class MultiWalletFinalizeComponent(
onEvent(it)
}
}

componentScope.launch {
backButtonClickFlow.collect { model.onBack() }
}
componentScope.launch {
model.onBackFlow.collect { onBack() }
}
}

@Composable
override fun Content(modifier: Modifier) {
val state by model.uiState.collectAsStateWithLifecycle()

BackHandler { model.onBack() }

MultiWalletFinalize(
state = state,
modifier = modifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ internal class MultiWalletFinalizeModel @Inject constructor(

private var walletHasBackupError = false
val uiState = _uiState.asStateFlow()
val onBackFlow = MutableSharedFlow<Unit>()

val onEvent = MutableSharedFlow<MultiWalletFinalizeComponent.Event>()

Expand All @@ -72,6 +73,12 @@ internal class MultiWalletFinalizeModel @Inject constructor(
}
}

fun onBack() {
if (uiState.value.scanPrimary) {
modelScope.launch { onBackFlow.emit(Unit) }
}
}

private fun getInitialState(): MultiWalletFinalizeUM {
val backupService = backupServiceHolder.backupService.get() ?: return MultiWalletFinalizeUM()
val initialStep = getInitialStep()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui

import androidx.compose.animation.*
import com.tangem.core.ui.extensions.stringResourceSafe
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
Expand All @@ -23,7 +24,6 @@ import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.*
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
Expand Down