Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-01 13:30:29 +05:00
parent 4c2ce375e9
commit 2cd8786c75
8 changed files with 133 additions and 159 deletions

View file

@ -0,0 +1,104 @@
package com.tangem.core.ui.components.grid
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
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.tooling.preview.Preview
import androidx.compose.ui.unit.LayoutDirection
import com.tangem.core.ui.components.grid.entity.EnumeratedTwoColumnGridItem
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
/**
* EnumeratedTwoColumnGrid component
*
* @param items component items
* @param modifier composable modifier
*
*/
@Composable
fun EnumeratedTwoColumnGrid(items: ImmutableList<EnumeratedTwoColumnGridItem>, modifier: Modifier = Modifier) {
VerticalGrid(
modifier = modifier,
items = items,
) { 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 <T> VerticalGrid(
items: ImmutableList<T>,
modifier: Modifier = Modifier,
crossinline content: @Composable (T) -> Unit,
) {
val columnLength = items.size / 2
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceEvenly,
) {
repeat(2) { index ->
Column {
for (i in 0 until columnLength) {
val item = items[index * columnLength + i]
content(item)
}
}
}
}
}
@Preview(widthDp = 360, heightDp = 640, showBackground = true)
@Preview(widthDp = 360, heightDp = 640, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun Preview() {
TangemThemePreview {
EnumeratedTwoColumnGrid(
items = List(24) {
EnumeratedTwoColumnGridItem(
index = it + 1,
mnemonic = "word${it + 1}",
)
}.toImmutableList(),
)
}
}

View file

@ -0,0 +1,6 @@
package com.tangem.core.ui.components.grid.entity
data class EnumeratedTwoColumnGridItem(
val index: Int,
val mnemonic: String,
)

View file

@ -1,14 +1,10 @@
package com.tangem.features.hotwallet.manualbackup.phrase.entity
import com.tangem.core.ui.components.grid.entity.EnumeratedTwoColumnGridItem
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
internal data class ManualBackupPhraseUM(
val onContinueClick: () -> Unit,
val words: ImmutableList<MnemonicGridItem> = persistentListOf(),
) {
data class MnemonicGridItem(
val index: Int,
val mnemonic: String,
)
}
val words: ImmutableList<EnumeratedTwoColumnGridItem> = persistentListOf(),
)

View file

@ -5,6 +5,7 @@ import arrow.core.getOrElse
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.components.grid.entity.EnumeratedTwoColumnGridItem
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.hotwallet.manualbackup.phrase.ManualBackupPhraseComponent
@ -51,7 +52,7 @@ internal class ManualBackupPhraseModel @Inject constructor(
uiState.update {
it.copy(
words = seedPhrasePrivateInfo.mnemonic.mnemonicComponents.mapIndexed { index, s ->
ManualBackupPhraseUM.MnemonicGridItem(index + 1, s)
EnumeratedTwoColumnGridItem(index + 1, s)
}.toImmutableList(),
)
}

View file

@ -7,20 +7,18 @@ 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.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.grid.EnumeratedTwoColumnGrid
import com.tangem.core.ui.components.grid.entity.EnumeratedTwoColumnGridItem
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.hotwallet.impl.R
import com.tangem.features.hotwallet.manualbackup.phrase.entity.ManualBackupPhraseUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
@Composable
@ -41,8 +39,8 @@ internal fun ManualBackupPhraseContent(state: ManualBackupPhraseUM, modifier: Mo
modifier = Modifier.padding(top = 20.dp),
)
SeedPhraseGridBlock(
mnemonicGridItems = state.words,
EnumeratedTwoColumnGrid(
items = state.words,
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, bottom = 32.dp),
@ -97,70 +95,6 @@ private fun TitleBlock(state: ManualBackupPhraseUM, modifier: Modifier = Modifie
}
}
@Composable
private fun SeedPhraseGridBlock(
mnemonicGridItems: ImmutableList<ManualBackupPhraseUM.MnemonicGridItem>,
modifier: Modifier = Modifier,
) {
VerticalGrid(
modifier = modifier,
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 <T> VerticalGrid(
items: ImmutableList<T>,
modifier: Modifier = Modifier,
crossinline content: @Composable (T) -> Unit,
) {
val columnLength = items.size / 2
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceEvenly,
) {
repeat(2) { index ->
Column {
for (i in 0 until columnLength) {
val item = items[index * columnLength + i]
content(item)
}
}
}
}
}
@Preview(showBackground = true, widthDp = 360, heightDp = 640)
@Preview(showBackground = true, widthDp = 360, heightDp = 640, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
@ -170,7 +104,7 @@ private fun Preview() {
state = ManualBackupPhraseUM(
onContinueClick = {},
words = List(12) {
ManualBackupPhraseUM.MnemonicGridItem(
EnumeratedTwoColumnGridItem(
index = it + 1,
mnemonic = "word${it + 1}",
)

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.builder
import com.tangem.core.ui.components.grid.entity.EnumeratedTwoColumnGridItem
import com.tangem.crypto.bip39.Mnemonic
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.GeneratedWordsType
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM
@ -20,10 +21,10 @@ internal class GenerateSeedPhraseUiStateBuilder(
option: GeneratedWordsType,
): MultiWalletSeedPhraseUM.GenerateSeedPhrase {
val words12 = generatedWords12.mnemonicComponents.mapIndexed { index, s ->
MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem(index + 1, s)
EnumeratedTwoColumnGridItem(index + 1, s)
}.toImmutableList()
val words24 = generatedWords24.mnemonicComponents.mapIndexed { index, s ->
MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem(index + 1, s)
EnumeratedTwoColumnGridItem(index + 1, s)
}.toImmutableList()
return MultiWalletSeedPhraseUM.GenerateSeedPhrase(
@ -45,8 +46,8 @@ internal class GenerateSeedPhraseUiStateBuilder(
private fun switchType(
newType: GeneratedWordsType,
generatedWords12: ImmutableList<MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem>,
generatedWords24: ImmutableList<MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem>,
generatedWords12: ImmutableList<EnumeratedTwoColumnGridItem>,
generatedWords24: ImmutableList<EnumeratedTwoColumnGridItem>,
) {
updateUiState { uiSt ->
changeGeneratedWordsType(newType)

View file

@ -5,15 +5,14 @@ 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.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.components.grid.EnumeratedTwoColumnGrid
import com.tangem.core.ui.components.grid.entity.EnumeratedTwoColumnGridItem
import com.tangem.core.ui.extensions.pluralStringResourceSafe
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
@ -21,8 +20,6 @@ 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.model.GeneratedWordsType
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
import kotlinx.collections.immutable.toImmutableList
@ -45,8 +42,8 @@ internal fun MultiWalletSeedPhraseWords(
TitleBlock(state)
SeedPhraseGridBlock(
mnemonicGridItems = state.words,
EnumeratedTwoColumnGrid(
items = state.words,
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, bottom = 32.dp),
@ -127,67 +124,6 @@ private fun TitleBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, modifi
}
}
@Composable
private fun SeedPhraseGridBlock(mnemonicGridItems: ImmutableList<MnemonicGridItem>, modifier: Modifier = Modifier) {
VerticalGrid(
modifier = modifier,
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 <T> VerticalGrid(
items: ImmutableList<T>,
modifier: Modifier = Modifier,
crossinline content: @Composable (T) -> Unit,
) {
val columnLength = items.size / 2
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceEvenly,
) {
repeat(2) { index ->
Column {
for (i in 0 until columnLength) {
val item = items[index * columnLength + i]
content(item)
}
}
}
}
}
@Preview(showBackground = true, heightDp = 640)
@Composable
private fun Preview() {
@ -195,7 +131,7 @@ private fun Preview() {
MultiWalletSeedPhraseWords(
state = MultiWalletSeedPhraseUM.GenerateSeedPhrase(
words = List(24) {
MnemonicGridItem(
EnumeratedTwoColumnGridItem(
index = it + 1,
mnemonic = "word1",
)

View file

@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.s
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.components.grid.entity.EnumeratedTwoColumnGridItem
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.onboarding.v2.common.ui.OnboardingDialogUM
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.GeneratedWordsType
@ -22,15 +23,10 @@ internal sealed class MultiWalletSeedPhraseUM(
data class GenerateSeedPhrase(
val option: GeneratedWordsType = GeneratedWordsType.Words12,
val words: ImmutableList<MnemonicGridItem> = persistentListOf(),
val words: ImmutableList<EnumeratedTwoColumnGridItem> = persistentListOf(),
val onOptionChange: (GeneratedWordsType) -> Unit = {},
val onContinueClick: () -> Unit = {},
) : MultiWalletSeedPhraseUM(order = 1) {
data class MnemonicGridItem(
val index: Int,
val mnemonic: String,
)
}
) : MultiWalletSeedPhraseUM(order = 1)
data class GeneratedWordsCheck(
val wordFields: ImmutableList<WordField> = persistentListOf(),