Updated on 2026-08-14
This commit is contained in:
parent
6ac5724e56
commit
a80542d5da
15 changed files with 354 additions and 169 deletions
|
|
@ -10,6 +10,7 @@ import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackA
|
|||
import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.*
|
||||
import com.arkivanov.decompose.value.Value
|
||||
import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
|
|
@ -19,10 +20,13 @@ import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletCo
|
|||
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.chooseoption.Wallet1ChooseOptionComponent
|
||||
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.model.OnboardingMultiWalletState
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState.Step.*
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.ui.OnboardingMultiWallet
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.ui.WalletArtworksState
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -35,6 +39,18 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
|
||||
private val model: OnboardingMultiWalletModel = getOrCreateModel(params)
|
||||
private val stackNavigation = StackNavigation<OnboardingMultiWalletState.Step>()
|
||||
private val artworksState = instanceKeeper.getOrCreateSimple {
|
||||
MutableStateFlow(
|
||||
when (model.state.value.currentStep) {
|
||||
CreateWallet -> WalletArtworksState.Folded
|
||||
ChooseBackupOption -> WalletArtworksState.Fan
|
||||
SeedPhrase -> WalletArtworksState.Hidden
|
||||
AddBackupDevice -> WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.First)
|
||||
FinishBackup -> WalletArtworksState.Stack()
|
||||
Done -> error("Done state should not be used as starting state")
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override val innerNavigation: InnerNavigation = object : InnerNavigation {
|
||||
override val state = MutableStateFlow(
|
||||
|
|
@ -47,50 +63,84 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
}
|
||||
}
|
||||
|
||||
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 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(
|
||||
CreateWallet -> MultiWalletCreateWalletComponent(
|
||||
context = childContext,
|
||||
params = MultiWalletChildParams(
|
||||
multiWalletState = model.state,
|
||||
parentParams = params,
|
||||
),
|
||||
onDone = ::onStepDone,
|
||||
onNextStep = ::handleNavigationEvent,
|
||||
)
|
||||
OnboardingMultiWalletState.Step.AddBackupDevice -> MultiWalletBackupComponent(
|
||||
ChooseBackupOption -> Wallet1ChooseOptionComponent(
|
||||
context = childContext,
|
||||
onNextStep = ::handleNavigationEvent,
|
||||
)
|
||||
SeedPhrase -> TODO()
|
||||
AddBackupDevice -> MultiWalletBackupComponent(
|
||||
context = childContext,
|
||||
params = MultiWalletChildParams(
|
||||
multiWalletState = model.state,
|
||||
parentParams = params,
|
||||
),
|
||||
onDone = ::onStepDone,
|
||||
onEvent = ::handleBackupComponentEvent,
|
||||
)
|
||||
OnboardingMultiWalletState.Step.FinishBackup -> TODO()
|
||||
OnboardingMultiWalletState.Step.Done -> TODO()
|
||||
FinishBackup -> TODO()
|
||||
Done -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onStepDone() {
|
||||
when (model.state.value.currentStep) {
|
||||
OnboardingMultiWalletState.Step.CreateWallet -> {
|
||||
stackNavigation.push(OnboardingMultiWalletState.Step.AddBackupDevice)
|
||||
// innerNavigation.state.value TODO
|
||||
fun handleNavigationEvent(nextStep: OnboardingMultiWalletState.Step) {
|
||||
when (nextStep) {
|
||||
ChooseBackupOption -> {
|
||||
artworksState.value = WalletArtworksState.Fan
|
||||
}
|
||||
SeedPhrase -> {
|
||||
artworksState.value = WalletArtworksState.Hidden
|
||||
}
|
||||
AddBackupDevice -> {
|
||||
artworksState.value = WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.First)
|
||||
}
|
||||
FinishBackup -> {
|
||||
}
|
||||
Done -> {
|
||||
// TODO
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
stackNavigation.push(nextStep)
|
||||
}
|
||||
|
||||
fun handleBackupComponentEvent(event: MultiWalletBackupComponent.Event) {
|
||||
when (event) {
|
||||
MultiWalletBackupComponent.Event.Done -> {
|
||||
// TODO navigate to finalize
|
||||
}
|
||||
MultiWalletBackupComponent.Event.OneDeviceAdded -> {
|
||||
artworksState.value = WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.Second)
|
||||
}
|
||||
MultiWalletBackupComponent.Event.TwoDeviceAdded -> {
|
||||
artworksState.value = WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.Third)
|
||||
}
|
||||
OnboardingMultiWalletState.Step.AddBackupDevice -> TODO()
|
||||
OnboardingMultiWalletState.Step.FinishBackup -> TODO()
|
||||
OnboardingMultiWalletState.Step.Done -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,10 +148,12 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
|
|||
override fun Content(modifier: Modifier) {
|
||||
val stackState by childStack.subscribeAsState()
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val artworksState by artworksState.collectAsStateWithLifecycle()
|
||||
|
||||
OnboardingMultiWallet(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
artworksState = artworksState,
|
||||
childContent = { mdfr ->
|
||||
Children(
|
||||
stack = stackState,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import kotlinx.coroutines.launch
|
|||
class MultiWalletBackupComponent(
|
||||
context: AppComponentContext,
|
||||
params: MultiWalletChildParams,
|
||||
onDone: () -> Unit,
|
||||
onEvent: (event: Event) -> Unit,
|
||||
) : AppComponentContext by context, MultiWalletChildComponent {
|
||||
|
||||
private val model: MultiWalletBackupModel = getOrCreateModel(params)
|
||||
|
|
@ -29,7 +29,7 @@ class MultiWalletBackupComponent(
|
|||
)
|
||||
|
||||
componentScope.launch {
|
||||
model.onDoneFlow.collect { onDone() }
|
||||
model.eventFlow.collect(onEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,4 +42,8 @@ class MultiWalletBackupComponent(
|
|||
state = state,
|
||||
)
|
||||
}
|
||||
|
||||
enum class Event {
|
||||
Done, OneDeviceAdded, TwoDeviceAdded
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository
|
|||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.MultiWalletBackupComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.backupCardAttestationFailedDialog
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.resetBackupCardDialog
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state.MultiWalletBackupUM
|
||||
|
|
@ -45,35 +46,31 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
|
||||
private val _uiState = MutableStateFlow(
|
||||
when (scanResponse.productType) {
|
||||
ProductType.Wallet -> getWallet1State()
|
||||
ProductType.Wallet,
|
||||
ProductType.Wallet2,
|
||||
ProductType.Ring,
|
||||
-> MultiWalletBackupUM.Wallet2(
|
||||
isRing = scanResponse.productType == ProductType.Ring,
|
||||
backupAdded = false, // backupService.hasIncompletedBackup,
|
||||
onAddBackupClick = {},
|
||||
onFinalizeButtonClick = {},
|
||||
)
|
||||
-> getInitState()
|
||||
else -> error("Type: ${scanResponse.productType.name} is not supported!")
|
||||
},
|
||||
)
|
||||
|
||||
val uiState: StateFlow<MultiWalletBackupUM> = _uiState
|
||||
val onDoneFlow = MutableSharedFlow<Unit>()
|
||||
val eventFlow = MutableSharedFlow<MultiWalletBackupComponent.Event>()
|
||||
|
||||
private fun getWallet1State(): MultiWalletBackupUM.Wallet1 {
|
||||
private fun getInitState(): MultiWalletBackupUM {
|
||||
return when (backupService.currentState) {
|
||||
BackupService.State.Preparing -> {
|
||||
MultiWalletBackupUM.Wallet1(
|
||||
MultiWalletBackupUM(
|
||||
title = resourceReference(R.string.onboarding_title_no_backup_cards),
|
||||
bodyText = resourceReference(R.string.onboarding_subtitle_no_backup_cards),
|
||||
showFinalizeButton = false,
|
||||
finalizeButtonEnabled = false,
|
||||
addBackupButtonEnabled = true,
|
||||
addBackupButtonLoading = false,
|
||||
artworkNumberOfBackupCards = 0,
|
||||
onAddBackupClick = ::startBackupWallet1,
|
||||
onAddBackupClick = ::startBackupWallet,
|
||||
onFinalizeButtonClick = {},
|
||||
onSkipButtonClick = { onDoneFlow.tryEmit(Unit) },
|
||||
onSkipButtonClick = {
|
||||
// eventFlow.tryEmit(Unit)
|
||||
},
|
||||
)
|
||||
}
|
||||
is BackupService.State.FinalizingBackupCard -> TODO()
|
||||
|
|
@ -82,7 +79,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun startBackupWallet1() {
|
||||
private fun startBackupWallet() {
|
||||
backupService.discardSavedBackup()
|
||||
val primaryCard = scanResponse.primaryCard
|
||||
|
||||
|
|
@ -95,35 +92,37 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun setNumberOfBackupCardsWallet1(number: Int) {
|
||||
// set state for Wallet1 for adding backup cards and disable button if there is more than 2 backup cards
|
||||
private fun setNumberOfBackupCards(number: Int) {
|
||||
// set state for adding backup cards and disable button if there is more than 2 backup cards
|
||||
_uiState.update { st ->
|
||||
if (st !is MultiWalletBackupUM.Wallet1) return@update st
|
||||
|
||||
when (number) {
|
||||
0 -> {
|
||||
st.copy(
|
||||
title = resourceReference(R.string.onboarding_title_no_backup_cards),
|
||||
bodyText = resourceReference(R.string.onboarding_subtitle_no_backup_cards),
|
||||
artworkNumberOfBackupCards = 0,
|
||||
addBackupButtonEnabled = true,
|
||||
)
|
||||
}
|
||||
1 -> {
|
||||
modelScope.launch {
|
||||
eventFlow.emit(MultiWalletBackupComponent.Event.OneDeviceAdded)
|
||||
}
|
||||
st.copy(
|
||||
title = resourceReference(R.string.onboarding_title_one_backup_card),
|
||||
bodyText = resourceReference(R.string.onboarding_subtitle_one_backup_card),
|
||||
artworkNumberOfBackupCards = 1,
|
||||
addBackupButtonEnabled = true,
|
||||
showFinalizeButton = true,
|
||||
finalizeButtonEnabled = true,
|
||||
)
|
||||
}
|
||||
2 -> {
|
||||
modelScope.launch {
|
||||
eventFlow.emit(MultiWalletBackupComponent.Event.TwoDeviceAdded)
|
||||
}
|
||||
st.copy(
|
||||
title = resourceReference(R.string.onboarding_title_two_backup_cards),
|
||||
bodyText = resourceReference(R.string.onboarding_subtitle_two_backup_cards),
|
||||
artworkNumberOfBackupCards = 2,
|
||||
addBackupButtonEnabled = false,
|
||||
finalizeButtonEnabled = true,
|
||||
)
|
||||
}
|
||||
else -> st.copy(addBackupButtonEnabled = false)
|
||||
|
|
@ -132,7 +131,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun addBackupCardWithService() {
|
||||
updateWallet1State { st ->
|
||||
_uiState.update { st ->
|
||||
st.copy(addBackupButtonLoading = true)
|
||||
}
|
||||
|
||||
|
|
@ -140,38 +139,37 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
backupService.skipCompatibilityChecks = false
|
||||
cardSdkConfigRepository.sdk.config.filter.cardIdFilter = null
|
||||
|
||||
updateWallet1State { st ->
|
||||
_uiState.update { st ->
|
||||
st.copy(addBackupButtonLoading = false)
|
||||
}
|
||||
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
// TODO change artwork
|
||||
state.update {
|
||||
it.copy(
|
||||
backupCards = it.backupCards + result.data,
|
||||
backupCardsNumber = it.backupCardsNumber + 1,
|
||||
)
|
||||
}
|
||||
setNumberOfBackupCardsWallet1(state.value.backupCardsNumber)
|
||||
setNumberOfBackupCards(state.value.backupCardsNumber)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
when (val error = result.error) {
|
||||
is TangemSdkError.BackupFailedNotEmptyWallets -> {
|
||||
updateWallet1State { st ->
|
||||
_uiState.update { st ->
|
||||
st.copy(
|
||||
dialog = resetBackupCardDialog(
|
||||
onReset = { resetBackupCard(cardId = error.cardId) },
|
||||
onDismiss = { updateWallet1State { it.copy(dialog = null) } },
|
||||
onDismiss = { _uiState.update { it.copy(dialog = null) } },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
is TangemSdkError.IssuerSignatureLoadingFailed -> {
|
||||
updateWallet1State { st ->
|
||||
_uiState.update { st ->
|
||||
st.copy(
|
||||
dialog = backupCardAttestationFailedDialog(
|
||||
onDismiss = { updateWallet1State { it.copy(dialog = null) } },
|
||||
onDismiss = { _uiState.update { it.copy(dialog = null) } },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -191,11 +189,4 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateWallet1State(block: (MultiWalletBackupUM.Wallet1) -> MultiWalletBackupUM.Wallet1) {
|
||||
_uiState.update { state ->
|
||||
if (state !is MultiWalletBackupUM.Wallet1) return@update state
|
||||
block(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,10 +24,7 @@ fun MultiWalletBackup(state: MultiWalletBackupUM, modifier: Modifier = Modifier)
|
|||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
) {
|
||||
when (state) {
|
||||
is MultiWalletBackupUM.Wallet1 -> Wallet1Content(state)
|
||||
is MultiWalletBackupUM.Wallet2 -> TODO()
|
||||
}
|
||||
Content(state)
|
||||
}
|
||||
|
||||
val dialog = state.dialog
|
||||
|
|
@ -54,7 +51,7 @@ fun MultiWalletBackup(state: MultiWalletBackupUM, modifier: Modifier = Modifier)
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ColumnScope.Wallet1Content(state: MultiWalletBackupUM.Wallet1) {
|
||||
private fun ColumnScope.Content(state: MultiWalletBackupUM) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -62,8 +59,6 @@ private fun ColumnScope.Wallet1Content(state: MultiWalletBackupUM.Wallet1) {
|
|||
.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
// artwork
|
||||
|
||||
Text(
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography.h2,
|
||||
|
|
@ -81,45 +76,25 @@ private fun ColumnScope.Wallet1Content(state: MultiWalletBackupUM.Wallet1) {
|
|||
)
|
||||
}
|
||||
|
||||
if (state.showFinalizeButton) {
|
||||
SecondaryButtonIconEnd(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
enabled = state.addBackupButtonEnabled,
|
||||
showProgress = state.addBackupButtonLoading,
|
||||
text = stringResource(R.string.onboarding_button_add_backup_card),
|
||||
onClick = state.onAddBackupClick,
|
||||
)
|
||||
SecondaryButtonIconEnd(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
enabled = state.addBackupButtonEnabled,
|
||||
showProgress = state.addBackupButtonLoading,
|
||||
text = stringResource(R.string.onboarding_button_add_backup_card),
|
||||
onClick = state.onAddBackupClick,
|
||||
)
|
||||
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.onboarding_button_finalize_backup),
|
||||
onClick = state.onFinalizeButtonClick,
|
||||
)
|
||||
} else {
|
||||
PrimaryButtonIconEnd(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
enabled = state.addBackupButtonEnabled,
|
||||
showProgress = state.addBackupButtonLoading,
|
||||
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(),
|
||||
text = stringResource(R.string.onboarding_button_skip_backup),
|
||||
onClick = state.onSkipButtonClick,
|
||||
)
|
||||
}
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.onboarding_button_finalize_backup),
|
||||
enabled = state.finalizeButtonEnabled,
|
||||
onClick = state.onFinalizeButtonClick,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
|
@ -127,25 +102,10 @@ private fun ColumnScope.Wallet1Content(state: MultiWalletBackupUM.Wallet1) {
|
|||
private fun PreviewWallet1() {
|
||||
TangemThemePreview {
|
||||
MultiWalletBackup(
|
||||
state = MultiWalletBackupUM.Wallet1(
|
||||
state = MultiWalletBackupUM(
|
||||
title = stringReference("Title"),
|
||||
bodyText = stringReference("Body body body"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewWallet2() {
|
||||
TangemThemePreview {
|
||||
MultiWalletBackup(
|
||||
state = MultiWalletBackupUM.Wallet2(
|
||||
isRing = false,
|
||||
backupAdded = true,
|
||||
onAddBackupClick = {},
|
||||
onFinalizeButtonClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +1,21 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state
|
||||
|
||||
import androidx.annotation.IntRange
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
||||
@Immutable
|
||||
sealed class MultiWalletBackupUM {
|
||||
|
||||
abstract val dialog: MultiWalletBackupUMDialog?
|
||||
|
||||
data class Wallet1(
|
||||
val title: TextReference = stringReference(""),
|
||||
val bodyText: TextReference = stringReference(""),
|
||||
val addBackupButtonEnabled: Boolean = true,
|
||||
val addBackupButtonLoading: Boolean = false,
|
||||
val showFinalizeButton: Boolean = false,
|
||||
val oneBackupAdded: Boolean = false,
|
||||
@IntRange(0, 2) val artworkNumberOfBackupCards: Int = 0, // highlights cards on 0, 1, 2
|
||||
val onAddBackupClick: () -> Unit = {},
|
||||
val onFinalizeButtonClick: () -> Unit = {},
|
||||
val onSkipButtonClick: () -> Unit = {},
|
||||
override val dialog: MultiWalletBackupUMDialog? = null,
|
||||
) : MultiWalletBackupUM()
|
||||
|
||||
data class Wallet2(
|
||||
val isRing: Boolean,
|
||||
val backupAdded: Boolean,
|
||||
val onAddBackupClick: () -> Unit,
|
||||
val onFinalizeButtonClick: () -> Unit,
|
||||
override val dialog: MultiWalletBackupUMDialog? = null,
|
||||
) : MultiWalletBackupUM()
|
||||
}
|
||||
data class MultiWalletBackupUM(
|
||||
val title: TextReference = stringReference(""),
|
||||
val bodyText: TextReference = stringReference(""),
|
||||
val addBackupButtonEnabled: Boolean = true,
|
||||
val addBackupButtonLoading: Boolean = false,
|
||||
val finalizeButtonEnabled: Boolean = false,
|
||||
val onAddBackupClick: () -> Unit = {},
|
||||
val onFinalizeButtonClick: () -> Unit = {},
|
||||
val onSkipButtonClick: () -> Unit = {},
|
||||
val dialog: MultiWalletBackupUMDialog? = null,
|
||||
)
|
||||
|
||||
data class MultiWalletBackupUMDialog(
|
||||
val title: TextReference,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildComponent
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.ui.Wallet1ChooseOption
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
|
||||
|
||||
class Wallet1ChooseOptionComponent(
|
||||
context: AppComponentContext,
|
||||
private val onNextStep: (OnboardingMultiWalletState.Step) -> Unit,
|
||||
) : AppComponentContext by context, MultiWalletChildComponent {
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
Wallet1ChooseOption(
|
||||
onBackupClick = {
|
||||
onNextStep(OnboardingMultiWalletState.Step.AddBackupDevice)
|
||||
},
|
||||
onScipClick = {
|
||||
onNextStep(OnboardingMultiWalletState.Step.Done)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.ui
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.TangemTheme
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
|
||||
@Composable
|
||||
fun Wallet1ChooseOption(onScipClick: () -> Unit, onBackupClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
verticalArrangement = Arrangement.Bottom,
|
||||
) {
|
||||
// val pagerState = rememberPagerState(pageCount = { 10 }) // TODO [REDACTED_TASK_KEY]
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 32.dp, end = 32.dp, bottom = 24.dp)
|
||||
.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_create_wallet_header),
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_create_wallet_body),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 12.dp),
|
||||
)
|
||||
}
|
||||
|
||||
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_backup_now),
|
||||
onClick = onBackupClick,
|
||||
)
|
||||
|
||||
SecondaryButton(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.onboarding_button_skip_backup),
|
||||
onClick = onScipClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,12 +12,13 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChild
|
|||
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 com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MultiWalletCreateWalletComponent(
|
||||
context: AppComponentContext,
|
||||
params: MultiWalletChildParams,
|
||||
onDone: () -> Unit,
|
||||
onNextStep: (OnboardingMultiWalletState.Step) -> Unit,
|
||||
) : AppComponentContext by context, MultiWalletChildComponent {
|
||||
|
||||
private val model: MultiWalletCreateWalletModel = getOrCreateModel(params)
|
||||
|
|
@ -28,7 +29,7 @@ class MultiWalletCreateWalletComponent(
|
|||
)
|
||||
|
||||
componentScope.launch {
|
||||
model.onDone.collect { onDone() }
|
||||
model.onDone.collect(onNextStep)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ 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.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
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.model.OnboardingMultiWalletState
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -36,15 +39,29 @@ class MultiWalletCreateWalletModel @Inject constructor(
|
|||
|
||||
private val _uiState = MutableStateFlow(
|
||||
MultiWalletCreateWalletUM(
|
||||
title = if (params.parentParams.withSeedPhraseFlow) {
|
||||
resourceReference(R.string.onboarding_create_wallet_options_title)
|
||||
} else {
|
||||
resourceReference(R.string.onboarding_create_wallet_header)
|
||||
},
|
||||
bodyText = if (params.parentParams.withSeedPhraseFlow) {
|
||||
resourceReference(R.string.onboarding_create_wallet_options_message)
|
||||
} else {
|
||||
resourceReference(R.string.onboarding_create_wallet_body)
|
||||
},
|
||||
onCreateWalletClick = { createWallet(false) },
|
||||
showSeedPhraseOption = params.parentParams.withSeedPhraseFlow,
|
||||
onOtherOptionsClick = { /* navigate */ },
|
||||
showOtherOptionsButton = params.parentParams.withSeedPhraseFlow,
|
||||
onOtherOptionsClick = {
|
||||
modelScope.launch {
|
||||
onDone.emit(OnboardingMultiWalletState.Step.SeedPhrase)
|
||||
}
|
||||
},
|
||||
dialog = null,
|
||||
),
|
||||
)
|
||||
|
||||
val uiState: StateFlow<MultiWalletCreateWalletUM> = _uiState
|
||||
val onDone = MutableSharedFlow<Unit>()
|
||||
val onDone = MutableSharedFlow<OnboardingMultiWalletState.Step>()
|
||||
|
||||
private fun createWallet(shouldReset: Boolean) {
|
||||
modelScope.launch {
|
||||
|
|
@ -66,7 +83,13 @@ class MultiWalletCreateWalletModel @Inject constructor(
|
|||
}
|
||||
|
||||
cardRepository.startCardActivation(cardId = result.data.card.cardId)
|
||||
onDone.emit(Unit)
|
||||
|
||||
if (params.parentParams.withSeedPhraseFlow) {
|
||||
onDone.emit(OnboardingMultiWalletState.Step.AddBackupDevice)
|
||||
} else {
|
||||
onDone.emit(OnboardingMultiWalletState.Step.ChooseBackupOption)
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
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.BasicDialog
|
||||
|
|
@ -11,6 +14,8 @@ 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.extensions.stringReference
|
||||
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.createwallet.ui.state.MultiWalletCreateWalletUM
|
||||
|
|
@ -40,6 +45,30 @@ fun MultiWalletCreateWallet(state: MultiWalletCreateWalletUM, modifier: Modifier
|
|||
.navigationBarsPadding(),
|
||||
verticalArrangement = Arrangement.Bottom,
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 32.dp, end = 32.dp, bottom = 24.dp)
|
||||
.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = state.bodyText.resolveReference(),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 12.dp),
|
||||
)
|
||||
}
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
|
||||
|
|
@ -49,24 +78,28 @@ fun MultiWalletCreateWallet(state: MultiWalletCreateWalletUM, modifier: Modifier
|
|||
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,
|
||||
)
|
||||
if (state.showOtherOptionsButton) {
|
||||
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
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TangemThemePreview {
|
||||
MultiWalletCreateWallet(
|
||||
state = MultiWalletCreateWalletUM(
|
||||
title = stringReference("Title"),
|
||||
bodyText = stringReference("Body body body"),
|
||||
onCreateWalletClick = {},
|
||||
showSeedPhraseOption = true,
|
||||
showOtherOptionsButton = true,
|
||||
onOtherOptionsClick = {},
|
||||
dialog = null,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
data class MultiWalletCreateWalletUM(
|
||||
val title: TextReference,
|
||||
val bodyText: TextReference,
|
||||
val showOtherOptionsButton: Boolean,
|
||||
val onCreateWalletClick: () -> Unit,
|
||||
val showSeedPhraseOption: Boolean,
|
||||
val onOtherOptionsClick: () -> Unit,
|
||||
val dialog: Dialog?,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,18 @@ data class OnboardingMultiWalletState(
|
|||
val currentStep: Step,
|
||||
val currentScanResponse: ScanResponse,
|
||||
) {
|
||||
/**
|
||||
* Wallet1
|
||||
* CreateWallet -> ChooseBackupOption -> AddBackupDevice -> FinishBackup -> [Done]
|
||||
* |
|
||||
* -> [Done]
|
||||
*
|
||||
* Wallet2/Ring
|
||||
* CreateWallet -> SeedPhrase -> AddBackupDevice -> FinishBackup -> [Done]
|
||||
* |
|
||||
* -> AddBackupDevice -> FinishBackup -> [Done]
|
||||
*/
|
||||
enum class Step {
|
||||
CreateWallet, AddBackupDevice, FinishBackup, Done
|
||||
CreateWallet, ChooseBackupOption, SeedPhrase, AddBackupDevice, FinishBackup, Done
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,8 @@ import com.tangem.features.onboarding.v2.impl.R
|
|||
fun screenTitleByStep(step: OnboardingMultiWalletState.Step): TextReference = when (step) {
|
||||
OnboardingMultiWalletState.Step.CreateWallet ->
|
||||
resourceReference(R.string.onboarding_create_wallet_header)
|
||||
OnboardingMultiWalletState.Step.ChooseBackupOption -> TODO()
|
||||
OnboardingMultiWalletState.Step.SeedPhrase -> TODO()
|
||||
OnboardingMultiWalletState.Step.AddBackupDevice ->
|
||||
resourceReference(R.string.onboarding_navbar_title_creating_backup)
|
||||
OnboardingMultiWalletState.Step.FinishBackup -> TODO()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.ui.state.OnboardingMul
|
|||
@Suppress("MagicNumber")
|
||||
internal fun OnboardingMultiWallet(
|
||||
state: OnboardingMultiWalletUM,
|
||||
artworksState: WalletArtworksState,
|
||||
modifier: Modifier = Modifier,
|
||||
childContent: @Composable (Modifier) -> Unit = {},
|
||||
) {
|
||||
|
|
@ -32,11 +33,15 @@ internal fun OnboardingMultiWallet(
|
|||
.padding(horizontal = 34.dp)
|
||||
.padding(top = 20.dp)
|
||||
.fillMaxWidth(),
|
||||
state = WalletArtworksState.Folded,
|
||||
state = artworksState,
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier.weight(.44f),
|
||||
modifier = if (artworksState == WalletArtworksState.Hidden) {
|
||||
Modifier.fillMaxSize()
|
||||
} else {
|
||||
Modifier.weight(.44f)
|
||||
},
|
||||
contentAlignment = Alignment.BottomStart,
|
||||
) {
|
||||
childContent(Modifier)
|
||||
|
|
@ -50,6 +55,7 @@ private fun Preview() {
|
|||
TangemThemePreview {
|
||||
OnboardingMultiWallet(
|
||||
state = OnboardingMultiWalletUM(artworkUrl = null),
|
||||
artworksState = WalletArtworksState.Folded,
|
||||
childContent = { md ->
|
||||
Box(
|
||||
modifier = md
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
@file:Suppress("MagicNumber", "UnnecessaryParentheses", "CyclomaticComplexMethod", "LongMethod")
|
||||
|
||||
package com.tangem.features.onboarding.v2.multiwallet.impl.ui
|
||||
|
||||
import androidx.compose.animation.core.Transition
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -20,12 +22,15 @@ import androidx.compose.ui.util.fastForEach
|
|||
import androidx.compose.ui.zIndex
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import kotlinx.coroutines.delay
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
sealed class WalletArtworksState {
|
||||
data object Hidden : WalletArtworksState()
|
||||
|
||||
data object Folded : WalletArtworksState()
|
||||
|
||||
data object Fan : WalletArtworksState()
|
||||
|
|
@ -54,6 +59,8 @@ sealed class WalletArtworksState {
|
|||
|
||||
@Composable
|
||||
fun WalletArtworks(url: String?, state: WalletArtworksState, modifier: Modifier = Modifier) {
|
||||
if (state is WalletArtworksState.Hidden) return
|
||||
|
||||
BoxWithConstraints(
|
||||
modifier
|
||||
.heightIn(min = 180.dp)
|
||||
|
|
@ -93,6 +100,21 @@ fun WalletArtworks(url: String?, state: WalletArtworksState, modifier: Modifier
|
|||
}
|
||||
}
|
||||
|
||||
val circleColor = TangemTheme.colors.background.secondary
|
||||
|
||||
Canvas(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(254.dp)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
drawCircle(
|
||||
color = circleColor,
|
||||
radius = size.width / 2,
|
||||
center = center,
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedWalletCards(
|
||||
url = url,
|
||||
modifier = Modifier
|
||||
|
|
@ -225,6 +247,7 @@ private fun WalletCard(url: String?, modifier: Modifier = Modifier) {
|
|||
|
||||
private fun WalletArtworksState.toTransitionSetState(maxWidthDp: Float, maxHeightDp: Float, density: Float) =
|
||||
when (this) {
|
||||
WalletArtworksState.Hidden -> listOf()
|
||||
is WalletArtworksState.Folded -> listOf(
|
||||
CardsTransitionState(
|
||||
WalletCardTransitionState(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue