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 97c2f1e5df..876f7de961 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 @@ -4,7 +4,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.arkivanov.decompose.FaultyDecomposeApi import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children +import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.fade 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 @@ -22,6 +24,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChild import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.MultiWalletBackupComponent import com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.Wallet1ChooseOptionComponent import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.MultiWalletCreateWalletComponent +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.MultiWalletSeedPhraseComponent 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.* @@ -30,6 +33,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.ui.WalletArtworksState import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor( @@ -44,7 +48,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor when (model.state.value.currentStep) { CreateWallet -> WalletArtworksState.Folded ChooseBackupOption -> WalletArtworksState.Fan - SeedPhrase -> WalletArtworksState.Hidden + SeedPhrase -> WalletArtworksState.Folded AddBackupDevice -> WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.First) FinishBackup -> WalletArtworksState.Stack() Done -> error("Done state should not be used as starting state") @@ -95,7 +99,15 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor context = childContext, onNextStep = ::handleNavigationEvent, ) - SeedPhrase -> TODO() + SeedPhrase -> MultiWalletSeedPhraseComponent( + context = childContext, + params = MultiWalletChildParams( + multiWalletState = model.state, + parentParams = params, + ), + onNextStep = ::handleNavigationEvent, + backButtonClickFlow = MutableSharedFlow(), + ) AddBackupDevice -> MultiWalletBackupComponent( context = childContext, params = MultiWalletChildParams( @@ -115,7 +127,6 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor artworksState.value = WalletArtworksState.Fan } SeedPhrase -> { - artworksState.value = WalletArtworksState.Hidden } AddBackupDevice -> { artworksState.value = WalletArtworksState.Unfold(WalletArtworksState.Unfold.Step.First) @@ -144,6 +155,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor } } + @OptIn(FaultyDecomposeApi::class) @Composable override fun Content(modifier: Modifier) { val stackState by childStack.subscribeAsState() @@ -154,10 +166,19 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor state = state, modifier = modifier, artworksState = artworksState, + isSeedPhraseState = stackState.active.configuration == SeedPhrase, childContent = { mdfr -> Children( stack = stackState, - animation = stackAnimation(slide()), + animation = stackAnimation( + selector = { one, two, direction -> + if (one.configuration == SeedPhrase || two.configuration == SeedPhrase) { + fade() + } else { + slide() + } + }, + ), ) { it.instance.Content(mdfr) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/MultiWalletSeedPhraseComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/MultiWalletSeedPhraseComponent.kt new file mode 100644 index 0000000000..89340f3ab8 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/MultiWalletSeedPhraseComponent.kt @@ -0,0 +1,44 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildComponent +import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.MultiWalletSeedPhraseModel +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.MultiWalletSeedPhrase +import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.launch + +@Suppress("UnusedPrivateMember") +class MultiWalletSeedPhraseComponent( + context: AppComponentContext, + params: MultiWalletChildParams, + onNextStep: (OnboardingMultiWalletState.Step) -> Unit, + backButtonClickFlow: SharedFlow, +) : AppComponentContext by context, MultiWalletChildComponent { + + private val model: MultiWalletSeedPhraseModel = getOrCreateModel() + + init { + componentScope.launch { + backButtonClickFlow.collect { + model.onBack() + } + } + } + + @Composable + override fun Content(modifier: Modifier) { + val state by model.uiState.collectAsStateWithLifecycle() + + MultiWalletSeedPhrase( + 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/seedphrase/model/MultiWalletSeedPhraseModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt new file mode 100644 index 0000000000..5dcc192bb2 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt @@ -0,0 +1,56 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model + +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.model.Model +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import javax.inject.Inject + +@ComponentScoped +class MultiWalletSeedPhraseModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, +) : Model() { + + private val state = MutableStateFlow(SeedPhraseState()) + + private val _uiState = MutableStateFlow( + MultiWalletSeedPhraseUM.Start( + onImportSeedPhraseClicked = {}, + onGenerateSeedPhraseClicked = { + openGeneratedSeedPhrase() + }, + onLearnMoreClicked = {}, + ), + ) + + val uiState = _uiState.asStateFlow() + + fun onBack() { + TODO("Not yet implemented") + } + + private fun openGeneratedSeedPhrase() { + // TODO state.value.generatedWords + val words = listOf("word, word") + + _uiState.value = MultiWalletSeedPhraseUM.GenerateSeedPhrase( + words24OptionSelected = false, + words = words.mapIndexed { index, s -> + MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem(index, s) + }.toImmutableList(), + onWords24OptionSwitch = { + _uiState.update { + if (it !is MultiWalletSeedPhraseUM.GenerateSeedPhrase) return@update it + it.copy(words24OptionSelected = it.words24OptionSelected.not()) + } + state.update { it.copy(words24Option = it.words24Option.not()) } + }, + onContinueClick = { + }, + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/SeedPhraseState.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/SeedPhraseState.kt new file mode 100644 index 0000000000..8b854a461c --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/SeedPhraseState.kt @@ -0,0 +1,6 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model + +data class SeedPhraseState( + val generatedWords: List? = null, + val words24Option: Boolean = false, +) \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhrase.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhrase.kt new file mode 100644 index 0000000000..2d220858a2 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhrase.kt @@ -0,0 +1,37 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.core.tween +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM + +@Composable +fun MultiWalletSeedPhrase(state: MultiWalletSeedPhraseUM, modifier: Modifier = Modifier) { + AnimatedContent( + modifier = modifier.navigationBarsPadding(), + targetState = state, + transitionSpec = { + val direction = if (initialState.order < targetState.order) { + AnimatedContentTransitionScope.SlideDirection.Start + } else { + AnimatedContentTransitionScope.SlideDirection.End + } + + slideIntoContainer(towards = direction, animationSpec = tween()) + .togetherWith(slideOutOfContainer(towards = direction, animationSpec = tween())) + }, + contentKey = { st -> st::class.java }, + label = "animatedContent", + ) { st -> + when (st) { + is MultiWalletSeedPhraseUM.Start -> MultiWalletSeedPhraseStart(state = st) + is MultiWalletSeedPhraseUM.GenerateSeedPhrase -> MultiWalletSeedPhraseWords(state = st) + is MultiWalletSeedPhraseUM.GeneratedWordsCheck -> MultiWalletSeedPhraseWordsCheck(state = st) + is MultiWalletSeedPhraseUM.Import -> MultiWalletSeedPhraseImport(state = st) + } + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseImport.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseImport.kt new file mode 100644 index 0000000000..532ac00f37 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseImport.kt @@ -0,0 +1,201 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui + +import androidx.compose.animation.* +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset +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.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.seedphrase.ui.state.MultiWalletSeedPhraseUM +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.utils.InvalidWordsColorTransformation +import kotlinx.collections.immutable.ImmutableList + +@Composable +fun MultiWalletSeedPhraseImport(state: MultiWalletSeedPhraseUM.Import, modifier: Modifier = Modifier) { + Box(modifier.fillMaxSize()) { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()), + ) { + Text( + text = stringResource(id = R.string.onboarding_seed_import_message), + style = TangemTheme.typography.body1, + color = TangemTheme.colors.text.secondary, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(start = 36.dp, end = 36.dp, top = 24.dp, bottom = 16.dp) + .fillMaxWidth(), + ) + + PhraseBlock( + state = state, + modifier = Modifier.padding(horizontal = 16.dp), + ) + + OutlineTextFieldWithIcon( + modifier = modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + value = state.passPhrase, + onValueChange = state.passPhraseChange, + iconResId = R.drawable.ic_information_24, + iconColor = TangemTheme.colors.icon.informative, + label = stringResource(id = R.string.common_passphrase), + placeholder = stringResource(id = R.string.send_optional_field), + onIconClick = state.onPassphraseInfoClick, + ) + + Box(Modifier.weight(1f)) { + PrimaryButtonIconEnd( + modifier = Modifier + .align(Alignment.BottomStart) + .padding(16.dp) + .fillMaxWidth(), + text = stringResource(id = R.string.common_import), + iconResId = R.drawable.ic_tangem_24, + enabled = state.createWalletEnabled, + showProgress = state.createWalletProgress, + onClick = state.createWalletClick, + ) + } + } + + val keyboard by keyboardAsState() + if (keyboard is Keyboard.Opened) { + SuggestionsBlock( + modifier = Modifier + .align(Alignment.BottomCenter) + .imePadding(), + suggestionsList = state.suggestionsList, + onClick = { index -> state.onSuggestionClick(state.suggestionsList[index]) }, + ) + } + } + + PassphraseInfoBottomSheet(state.infoBottomSheetConfig) +} + +@Composable +private fun PhraseBlock(state: MultiWalletSeedPhraseUM.Import, modifier: Modifier = Modifier) { + val warningColor = TangemTheme.colors.text.warning + val invalidWordsColorTransformation = remember(state.invalidWords, warningColor) { + InvalidWordsColorTransformation( + wordsToBrush = state.invalidWords, + style = SpanStyle(color = warningColor), + ) + } + + Column( + modifier = modifier.fillMaxWidth(), + ) { + OutlinedTextField( + modifier = Modifier + .fillMaxWidth() + .height(TangemTheme.dimens.size142), + value = state.passPhrase, + onValueChange = state.passPhraseChange, + textStyle = TangemTheme.typography.body1, + singleLine = false, + visualTransformation = invalidWordsColorTransformation, + ) + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .height(TangemTheme.dimens.size32), + ) { + if (state.wordsErrorText != null) { + Text( + modifier = Modifier.fillMaxSize(), + text = state.wordsErrorText.resolveReference(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.warning, + ) + } + } + } +} + +@Composable +private fun SuggestionsBlock( + suggestionsList: ImmutableList, + onClick: (Int) -> Unit, + modifier: Modifier = Modifier, +) { + AnimatedVisibility( + modifier = modifier, + enter = fadeIn() + slideIn(initialOffset = { IntOffset(x = 200, y = 0) }), + exit = slideOut(targetOffset = { IntOffset(x = -200, y = 0) }) + fadeOut(), + visible = suggestionsList.isNotEmpty(), + ) { + LazyRow( + contentPadding = PaddingValues(horizontal = TangemTheme.dimens.size16), + ) { + items(suggestionsList.size) { index -> + SuggestionButton( + modifier = Modifier.rowPadding( + index = index, + rowSize = suggestionsList.size, + outSide = TangemTheme.dimens.size0, + inSide = TangemTheme.dimens.size4, + ), + text = suggestionsList[index], + onClick = { onClick(index) }, + ) + } + } + } +} + +@Composable +private fun SuggestionButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier) { + Box(modifier = modifier.clickable(onClick = onClick)) { + Notifier( + text = text, + backgroundColor = TangemTheme.colors.icon.primary1, + textColor = TangemTheme.colors.text.primary2, + ) + } +} + +private fun Modifier.rowPadding(index: Int, rowSize: Int, outSide: Dp, inSide: Dp): Modifier = when (index) { + 0 -> this.padding(start = outSide, end = inSide) + rowSize - 1 -> this.padding(start = inSide, end = outSide) + else -> this.padding(horizontal = inSide) +} + +@Preview(showBackground = true) +@Composable +private fun Preview() { + TangemThemePreview( + alwaysShowBottomSheets = false, + ) { + MultiWalletSeedPhraseImport( + state = MultiWalletSeedPhraseUM.Import( + wordsErrorText = stringReference("Error"), + ), + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseStart.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseStart.kt new file mode 100644 index 0000000000..aff9adb6f1 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseStart.kt @@ -0,0 +1,158 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui + +import androidx.compose.foundation.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.style.LineBreak +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.SecondaryButton +import com.tangem.core.ui.components.SpacerH32 +import com.tangem.core.ui.components.SpacerW8 +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.seedphrase.ui.state.MultiWalletSeedPhraseUM + +@Composable +internal fun MultiWalletSeedPhraseStart(state: MultiWalletSeedPhraseUM.Start, modifier: Modifier = Modifier) { + Column( + modifier.padding(top = 48.dp), + ) { + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + .weight(1f), + verticalArrangement = Arrangement.spacedBy(28.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon( + modifier = Modifier.size(56.dp), + imageVector = ImageVector.vectorResource(R.drawable.ic_onboarding_text_edit_56), + contentDescription = null, + ) + Box( + modifier = Modifier + .background( + color = TangemTheme.colors.icon.warning.copy(alpha = 0.12f), + shape = RoundedCornerShape(TangemTheme.dimens.radius8), + ), + ) { + Text( + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.size12, vertical = TangemTheme.dimens.size4), + text = stringResource(id = R.string.onboarding_seed_phrase_intro_legacy), + color = TangemTheme.colors.text.warning, + style = TangemTheme.typography.body1, + ) + } + BodyContent(state) + } + SpacerH32() + Buttons(state) + } +} + +@Composable +private fun BodyContent(state: MultiWalletSeedPhraseUM.Start, modifier: Modifier = Modifier) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + Text( + text = stringResource(id = R.string.onboarding_seed_intro_title), + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + ) + Text( + text = stringResource(id = R.string.onboarding_seed_intro_message), + style = TangemTheme.typography.body1 + .copy(lineBreak = LineBreak.Paragraph), + color = TangemTheme.colors.text.secondary, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(horizontal = 32.dp) + .fillMaxWidth(), + ) + ReadMoreBlock(state) + } +} + +@Composable +private fun ReadMoreBlock(state: MultiWalletSeedPhraseUM.Start, modifier: Modifier = Modifier) { + Box( + modifier = modifier + .fillMaxWidth() + .padding(top = 16.dp), + ) { + val shape = TangemTheme.shapes.roundedCornersLarge + Row( + modifier = Modifier + .align(Alignment.Center) + .clip(shape) + .border( + width = 1.dp, + color = TangemTheme.colors.stroke.primary, + shape = shape, + ) + .clickable(onClick = state.onLearnMoreClicked) + .padding(horizontal = 16.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.Center, + ) { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.ic_arrow_top_right_24), + contentDescription = null, + tint = TangemTheme.colors.icon.primary1, + ) + SpacerW8() + Text( + modifier = Modifier.align(Alignment.CenterVertically), + style = TangemTheme.typography.button, + text = stringResource(id = R.string.onboarding_seed_button_read_more), + ) + } + } +} + +@Composable +private fun Buttons(state: MultiWalletSeedPhraseUM.Start, modifier: Modifier = Modifier) { + Column( + modifier = modifier + .padding(start = 16.dp, end = 16.dp, bottom = 16.dp) + .imePadding(), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + SecondaryButton( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.onboarding_seed_intro_button_generate), + onClick = state.onGenerateSeedPhraseClicked, + ) + SecondaryButton( + modifier = Modifier + .fillMaxWidth(), + text = stringResource(id = R.string.onboarding_seed_intro_button_import), + onClick = state.onImportSeedPhraseClicked, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun Preview() { + TangemThemePreview { + MultiWalletSeedPhraseStart( + state = MultiWalletSeedPhraseUM.Start(), + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt new file mode 100644 index 0000000000..bba9e89256 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt @@ -0,0 +1,208 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.res.pluralStringResource +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.LayoutDirection +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.PrimaryButton +import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons +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.seedphrase.ui.state.MultiWalletSeedPhraseUM +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +@Composable +fun MultiWalletSeedPhraseWords(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, modifier: Modifier = Modifier) { + Column(modifier.fillMaxSize()) { + SegmentSeedBlock( + modifier = Modifier.padding(vertical = 20.dp), + state = state, + ) + + TitleBlock(state) + + SeedPhraseGridBlock( + mnemonicGridItems = state.words, + modifier = Modifier + .padding(top = 20.dp, bottom = 92.dp), + ) + + Box(Modifier.weight(1f)) { + PrimaryButton( + modifier = Modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, bottom = 16.dp), + text = stringResource(id = R.string.common_continue), + onClick = state.onContinueClick, + ) + } + } +} + +@Suppress("ComplexCondition", "MagicNumber") +@Composable +private fun SegmentSeedBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, modifier: Modifier = Modifier) { + SegmentedButtons( + modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing76), + config = persistentListOf(0, 1), + initialSelectedItem = if (state.words24OptionSelected.not()) 0 else 1, + onClick = { + if (state.words24OptionSelected && it == 1 || state.words24OptionSelected.not() && it == 0) { + state.onWords24OptionSwitch() + } + }, + ) { + Text( + text = pluralStringResource( + id = R.plurals.onboarding_seed_generate_words_count, + count = if (it == 0) 12 else 24, + if (it == 0) 12 else 24, + ), + modifier = Modifier + .padding(vertical = TangemTheme.dimens.spacing10) + .fillMaxWidth(), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + ) + } +} + +@Suppress("MagicNumber") +@Composable +private fun TitleBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, modifier: Modifier = Modifier) { + Column( + modifier = modifier + .padding(horizontal = TangemTheme.dimens.size36) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + Text( + text = stringResource(id = R.string.onboarding_seed_generate_title), + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth(), + ) + Text( + text = pluralStringResource( + id = R.plurals.onboarding_seed_generate_message_words_count, + count = if (state.words24OptionSelected.not()) 12 else 24, + if (state.words24OptionSelected.not()) 12 else 24, + ), + style = TangemTheme.typography.body1, + color = TangemTheme.colors.text.secondary, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth(), + ) + } +} + +@Composable +private fun SeedPhraseGridBlock(mnemonicGridItems: ImmutableList, modifier: Modifier = Modifier) { + VerticalGrid( + modifier = modifier + .verticalScroll(rememberScrollState()), + items = mnemonicGridItems, + ) { item -> + Row( + modifier = Modifier.padding(all = TangemTheme.dimens.size8), + verticalAlignment = Alignment.CenterVertically, + ) { + if (LocalLayoutDirection.current == LayoutDirection.Ltr) { + Text( + modifier = Modifier.width(TangemTheme.dimens.size40), + text = "${item.index}.", + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.secondary, + ) + Text( + text = item.mnemonic, + style = TangemTheme.typography.button, + color = TangemTheme.colors.text.primary1, + ) + } else { + Text( + text = item.mnemonic, + style = TangemTheme.typography.button, + color = TangemTheme.colors.text.primary1, + ) + Text( + modifier = Modifier.width(TangemTheme.dimens.size40), + text = "${item.index}.", + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.secondary, + ) + } + } + } +} + +@Composable +private inline fun VerticalGrid( + items: ImmutableList, + modifier: Modifier = Modifier, + crossinline content: @Composable (T) -> Unit, +) { + val columnLength = items.size / 2 + Row( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly, + ) { + for (index in 0 until 2) { + Column { + for (i in 0 until columnLength) { + val item = items[index * columnLength + i] + content(item) + } + } + } + } +} + +@Preview(showBackground = true) +@Composable +private fun Preview() { + TangemThemePreview { + MultiWalletSeedPhraseWords( + state = MultiWalletSeedPhraseUM.GenerateSeedPhrase( + words = persistentListOf( + MnemonicGridItem( + index = 0, + mnemonic = "word1", + ), + MnemonicGridItem( + index = 1, + mnemonic = "word1", + ), + MnemonicGridItem( + index = 2, + mnemonic = "word1", + ), + MnemonicGridItem( + index = 3, + mnemonic = "word1", + ), + MnemonicGridItem( + index = 4, + mnemonic = "word1", + ), + ), + ), + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWordsCheck.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWordsCheck.kt new file mode 100644 index 0000000000..8f26de11b8 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWordsCheck.kt @@ -0,0 +1,122 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +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.input.TextFieldValue +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.R +import com.tangem.core.ui.components.OutlineTextField +import com.tangem.core.ui.components.PrimaryButtonIconEnd +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM +import kotlinx.collections.immutable.persistentListOf + +@Composable +fun MultiWalletSeedPhraseWordsCheck( + state: MultiWalletSeedPhraseUM.GeneratedWordsCheck, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()), + ) { + Text( + text = stringResource(R.string.onboarding_seed_user_validation_title), + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(top = 48.dp, start = 36.dp, end = 36.dp, bottom = 16.dp) + .fillMaxWidth(), + ) + Text( + text = stringResource(R.string.onboarding_seed_user_validation_message), + style = TangemTheme.typography.body1, + color = TangemTheme.colors.text.secondary, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(horizontal = 36.dp) + .fillMaxWidth(), + ) + + Fields( + state = state, + modifier = Modifier + .padding(vertical = 30.dp, horizontal = 16.dp), + ) + + Box( + Modifier.weight(1f), + ) { + PrimaryButtonIconEnd( + modifier = Modifier + .align(Alignment.BottomStart) + .padding(16.dp) + .fillMaxWidth(), + text = stringResource(id = R.string.onboarding_create_wallet_button_create_wallet), + iconResId = R.drawable.ic_tangem_24, + enabled = state.createWalletButtonEnabled, + showProgress = state.createWalletButtonProgress, + onClick = state.onCreateWalletButtonClick, + ) + } + } +} + +@Composable +private fun Fields(state: MultiWalletSeedPhraseUM.GeneratedWordsCheck, modifier: Modifier = Modifier) { + Column( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + state.wordFields.forEach { field -> + OutlineTextField( + value = field.word, + onValueChange = field.onChange, + label = field.index.toString(), + isError = field.error, + ) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun Preview() { + TangemThemePreview { + MultiWalletSeedPhraseWordsCheck( + state = MultiWalletSeedPhraseUM.GeneratedWordsCheck( + wordFields = persistentListOf( + MultiWalletSeedPhraseUM.GeneratedWordsCheck.WordField( + index = 2, + word = TextFieldValue(text = "word"), + onChange = {}, + error = false, + ), + MultiWalletSeedPhraseUM.GeneratedWordsCheck.WordField( + index = 7, + word = TextFieldValue(text = "wor"), + onChange = {}, + error = true, + ), + MultiWalletSeedPhraseUM.GeneratedWordsCheck.WordField( + index = 11, + word = TextFieldValue(text = "word"), + onChange = {}, + error = false, + ), + ), + ), + ) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/PassphraseInfoBottomSheet.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/PassphraseInfoBottomSheet.kt new file mode 100644 index 0000000000..fdf30402ea --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/PassphraseInfoBottomSheet.kt @@ -0,0 +1,90 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +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.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.PrimaryButton +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.onboarding.v2.impl.R + +@Composable +fun PassphraseInfoBottomSheet(config: TangemBottomSheetConfig) { + TangemBottomSheet( + config = config, + containerColor = TangemTheme.colors.background.primary, + ) { _: TangemBottomSheetConfigContent.Empty -> + PassphraseInfoBottomSheetContent(config.onDismissRequest) + } +} + +@Composable +fun PassphraseInfoBottomSheetContent(onDismiss: () -> Unit) { + Column( + modifier = Modifier + .background(color = TangemTheme.colors.background.primary) + .fillMaxWidth(), + ) { + Icon( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(top = TangemTheme.dimens.size40) + .size(TangemTheme.dimens.size48), + painter = painterResource(id = R.drawable.ic_information_24), + tint = TangemTheme.colors.icon.accent, + contentDescription = null, + ) + + Text( + text = stringResource(id = R.string.common_passphrase), + modifier = Modifier + .padding(top = TangemTheme.dimens.size40) + .align(Alignment.CenterHorizontally), + color = TangemTheme.colors.text.primary1, + style = TangemTheme.typography.h2, + ) + + Text( + text = stringResource(id = R.string.onboarding_bottom_sheet_passphrase_description), + modifier = Modifier + .padding(top = TangemTheme.dimens.size16) + .padding(horizontal = TangemTheme.dimens.size24) + .align(Alignment.CenterHorizontally), + color = TangemTheme.colors.text.secondary, + style = TangemTheme.typography.body2, + textAlign = TextAlign.Center, + ) + + PrimaryButton( + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.size16) + .padding(top = TangemTheme.dimens.size40) + .padding(bottom = TangemTheme.dimens.size32) + .fillMaxWidth(), + text = stringResource(id = R.string.common_ok), + onClick = onDismiss, + ) + } +} + +@Preview +@Composable +private fun PassphraseInfoBottomSheetContentPreview() { + TangemThemePreview { + PassphraseInfoBottomSheetContent({ }) + } +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/state/MultiWalletSeedPhraseUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/state/MultiWalletSeedPhraseUM.kt new file mode 100644 index 0000000000..84e5b22628 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/state/MultiWalletSeedPhraseUM.kt @@ -0,0 +1,62 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state + +import androidx.compose.runtime.Immutable +import androidx.compose.ui.text.input.TextFieldValue +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.core.ui.extensions.TextReference +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +@Immutable +sealed class MultiWalletSeedPhraseUM( + val order: Int, +) { + + data class Start( + val onLearnMoreClicked: () -> Unit = {}, + val onGenerateSeedPhraseClicked: () -> Unit = {}, + val onImportSeedPhraseClicked: () -> Unit = {}, + ) : MultiWalletSeedPhraseUM(order = 0) + + data class GenerateSeedPhrase( + val words24OptionSelected: Boolean = false, + val words: ImmutableList = persistentListOf(), + val onWords24OptionSwitch: () -> Unit = {}, + val onContinueClick: () -> Unit = {}, + ) : MultiWalletSeedPhraseUM(order = 1) { + data class MnemonicGridItem( + val index: Int, + val mnemonic: String, + ) + } + + data class GeneratedWordsCheck( + val wordFields: ImmutableList = persistentListOf(), + val createWalletButtonEnabled: Boolean = false, + val createWalletButtonProgress: Boolean = false, + val onCreateWalletButtonClick: () -> Unit = {}, + ) : MultiWalletSeedPhraseUM(order = 2) { + data class WordField( + val index: Int, + val word: TextFieldValue, + val error: Boolean, + val onChange: (TextFieldValue) -> Unit, + ) + } + + data class Import( + val words: TextFieldValue = TextFieldValue(""), + val wordsChange: (TextFieldValue) -> Unit = {}, + val passPhrase: TextFieldValue = TextFieldValue(""), + val passPhraseChange: (TextFieldValue) -> Unit = {}, + val onPassphraseInfoClick: () -> Unit = {}, + val wordsErrorText: TextReference? = null, + val invalidWords: ImmutableList = persistentListOf(), + val createWalletEnabled: Boolean = false, + val createWalletProgress: Boolean = false, + val createWalletClick: () -> Unit = {}, + val suggestionsList: ImmutableList = persistentListOf(), + val onSuggestionClick: (String) -> Unit = {}, + val infoBottomSheetConfig: TangemBottomSheetConfig = TangemBottomSheetConfig.Empty, + ) : MultiWalletSeedPhraseUM(order = 1) +} \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/utils/InvalidWordsColorTransformation.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/utils/InvalidWordsColorTransformation.kt new file mode 100644 index 0000000000..1650f7cd62 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/utils/InvalidWordsColorTransformation.kt @@ -0,0 +1,77 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.utils + +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.input.OffsetMapping +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation +import com.tangem.utils.extensions.isSingleItem +import kotlinx.collections.immutable.ImmutableList + +class InvalidWordsColorTransformation( + private val wordsToBrush: ImmutableList, + private val style: SpanStyle, +) : VisualTransformation { + + override fun filter(text: AnnotatedString): TransformedText { + val plainText = text.text + if (wordsToBrush.isSingleItem() && wordsToBrush.first() == plainText) { + return plainText.annotate().toTransformedText() + } + + val wordList = makeSeparatedWordlist(plainText) + val annotatedString = makeAnnotatedString(wordList) + + return annotatedString.toTransformedText() + } + + private fun makeSeparatedWordlist(plainText: String): List { + val plainTextCharArray = plainText.toCharArray() + val wordlist = mutableListOf() + var wordBuilder = StringBuilder() + + for (index in plainTextCharArray.indices) { + val char = plainTextCharArray[index] + if (char.isWhitespace()) { + if (wordBuilder.isEmpty()) { + wordlist.add(WORD_SEPARATOR) + } else { + wordlist.add(wordBuilder.toString()) + wordBuilder = StringBuilder() + wordlist.add(WORD_SEPARATOR) + } + } else { + if (index == plainTextCharArray.lastIndex) { + wordBuilder.append(char) + wordlist.add(wordBuilder.toString()) + wordBuilder = StringBuilder() + } else { + wordBuilder.append(char) + } + } + } + return wordlist.toList() + } + + private fun makeAnnotatedString(wordList: List): AnnotatedString = buildAnnotatedString { + wordList.forEach { + if (it == WORD_SEPARATOR) { + append(WHITE_SPACE) + } else if (wordsToBrush.contains(it)) { + append(it.annotate()) + } else { + append(it) + } + } + } + + private fun String.annotate(): AnnotatedString = AnnotatedString(this, style) + + private fun AnnotatedString.toTransformedText(): TransformedText = TransformedText(this, OffsetMapping.Identity) + + companion object { + private const val WHITE_SPACE = " " + private const val WORD_SEPARATOR = "_$@-*" + } +} \ 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 363655f367..d1df99ba69 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 @@ -6,6 +6,7 @@ import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletCo 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.child.seedphrase.model.MultiWalletSeedPhraseModel import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletModel import dagger.Binds import dagger.Module @@ -42,4 +43,9 @@ internal interface ModelModule { @IntoMap @ClassKey(MultiWalletCreateWalletModel::class) fun provideModel3(model: MultiWalletCreateWalletModel): Model + + @Binds + @IntoMap + @ClassKey(MultiWalletSeedPhraseModel::class) + fun provideModel4(model: MultiWalletSeedPhraseModel): Model } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt index f26fbb2cd4..c698e7e721 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt @@ -2,8 +2,6 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.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 @@ -18,33 +16,32 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.ui.state.OnboardingMul internal fun OnboardingMultiWallet( state: OnboardingMultiWalletUM, artworksState: WalletArtworksState, + isSeedPhraseState: Boolean, modifier: Modifier = Modifier, childContent: @Composable (Modifier) -> Unit = {}, ) { Column( - modifier = modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()), + modifier = modifier.fillMaxSize(), ) { - WalletArtworks( - url = state.artworkUrl, - modifier = Modifier - .weight(.56f) - .padding(horizontal = 34.dp) - .padding(top = 20.dp) - .fillMaxWidth(), - state = artworksState, - ) + if (isSeedPhraseState.not()) { + WalletArtworks( + url = state.artworkUrl, + modifier = Modifier + .weight(.56f) + .padding(horizontal = 34.dp) + .padding(top = 20.dp) + .fillMaxWidth(), + state = artworksState, + ) - Box( - modifier = if (artworksState == WalletArtworksState.Hidden) { - Modifier.fillMaxSize() - } else { - Modifier.weight(.44f) - }, - contentAlignment = Alignment.BottomStart, - ) { - childContent(Modifier) + Box( + modifier = Modifier.weight(.44f), + contentAlignment = Alignment.BottomStart, + ) { + childContent(Modifier) + } + } else { + childContent(Modifier.fillMaxSize()) } } } @@ -56,6 +53,7 @@ private fun Preview() { OnboardingMultiWallet( state = OnboardingMultiWalletUM(artworkUrl = null), artworksState = WalletArtworksState.Folded, + isSeedPhraseState = false, childContent = { md -> Box( modifier = md @@ -66,4 +64,23 @@ private fun Preview() { }, ) } +} + +@Preview(showBackground = true, widthDp = 360, heightDp = 640) +@Composable +private fun Preview2() { + TangemThemePreview { + OnboardingMultiWallet( + state = OnboardingMultiWalletUM(artworkUrl = null), + artworksState = WalletArtworksState.Folded, + isSeedPhraseState = true, + childContent = { md -> + Box( + modifier = md + .background(Color.DarkGray) + .fillMaxSize(), + ) + }, + ) + } } \ No newline at end of file