Updated on 2026-08-14

This commit is contained in:
Tangem 2025-02-13 15:11:36 +03:00
parent 4e0089d3d2
commit a85078c180
8 changed files with 85 additions and 42 deletions

View file

@ -9,7 +9,7 @@ import com.tangem.sdk.extensions.getWordlist
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
class MnemonicRepository @Inject constructor(
internal class MnemonicRepository @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val wordlist = Wordlist.getWordlist(context)

View file

@ -50,8 +50,8 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
private val params = paramsContainer.require<MultiWalletChildParams>()
private val multiWalletState get() = params.multiWalletState
private val state = MutableStateFlow(SeedPhraseState())
private val _uiState = MutableStateFlow(getStartState())
private val state = MutableStateFlow(getInitialSeedPhraseState())
private val _uiState = MutableStateFlow(getInitialUIState())
private val generateSeedPhraseUiStateBuilder = GenerateSeedPhraseUiStateBuilder(
updateUiState = { block -> updateUiStateSpecific(block) },
@ -60,7 +60,9 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
// =============================================
// | DON'T FIXME !!! MODIFY WITH CAUTION !!! |
// =============================================
changeWords24Option = { state.update { it.copy(words24Option = it.words24Option) } },
changeGeneratedWordsType = { newType ->
state.update { st -> st.copy(generatedWordsType = newType) }
},
// =============================================
)
@ -75,10 +77,9 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
// =============================================
importWallet = importWallet@{
importWallet(
mnemonic = if (state.value.words24Option) {
state.value.generatedWords24 ?: return@importWallet
} else {
state.value.generatedWords12 ?: return@importWallet
mnemonic = when (state.value.generatedWordsType) {
GeneratedWordsType.Words12 -> state.value.generatedWords12 ?: return@importWallet
GeneratedWordsType.Words24 -> state.value.generatedWords24 ?: return@importWallet
},
passphrase = null,
generatedSeedPhrase = true,
@ -91,6 +92,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
modelScope = modelScope,
mnemonicRepository = mnemonicRepository,
updateUiState = { block -> updateUiStateSpecific(block) },
readyToImport = { ready -> state.update { it.copy(readyToImport = ready) } },
importWallet = { mnemonic, passphrase ->
importWallet(
mnemonic = mnemonic,
@ -112,8 +114,8 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
is MultiWalletSeedPhraseUM.Import,
is MultiWalletSeedPhraseUM.GenerateSeedPhrase,
-> {
_uiState.value = getStartState()
state.value = SeedPhraseState()
_uiState.value = getInitialUIState()
state.value = getInitialSeedPhraseState()
}
is MultiWalletSeedPhraseUM.GeneratedWordsCheck -> {
openGeneratedSeedPhrase()
@ -121,7 +123,16 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
}
}
private fun getStartState(): MultiWalletSeedPhraseUM {
private fun getInitialSeedPhraseState(): SeedPhraseState {
return SeedPhraseState(
generatedWords12 = null,
generatedWords24 = null,
generatedWordsType = GeneratedWordsType.Words12,
readyToImport = false,
)
}
private fun getInitialUIState(): MultiWalletSeedPhraseUM {
return MultiWalletSeedPhraseUM.Start(
onImportSeedPhraseClicked = {
openImportSeedPhrase()
@ -143,6 +154,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
_uiState.value = generateSeedPhraseUiStateBuilder.getState(
generatedWords12 = words12,
generatedWords24 = words24,
option = state.value.generatedWordsType,
)
}

View file

@ -2,9 +2,14 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.mode
import com.tangem.crypto.bip39.Mnemonic
data class SeedPhraseState(
val generatedWords12: Mnemonic? = null,
val generatedWords24: Mnemonic? = null,
val words24Option: Boolean = false,
val readyToImport: Boolean = false,
)
internal data class SeedPhraseState(
val generatedWords12: Mnemonic?,
val generatedWords24: Mnemonic?,
val generatedWordsType: GeneratedWordsType,
val readyToImport: Boolean,
)
internal enum class GeneratedWordsType(val length: Int) {
Words12(12),
Words24(24),
}

View file

@ -1,19 +1,24 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.builder
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
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
internal class GenerateSeedPhraseUiStateBuilder(
private val changeWords24Option: (Boolean) -> Unit,
private val changeGeneratedWordsType: (GeneratedWordsType) -> Unit,
private val updateUiState: (
(MultiWalletSeedPhraseUM.GenerateSeedPhrase) -> MultiWalletSeedPhraseUM.GenerateSeedPhrase,
) -> Unit,
private val onContinue: () -> Unit,
) {
fun getState(generatedWords12: Mnemonic, generatedWords24: Mnemonic): MultiWalletSeedPhraseUM.GenerateSeedPhrase {
fun getState(
generatedWords12: Mnemonic,
generatedWords24: Mnemonic,
option: GeneratedWordsType,
): MultiWalletSeedPhraseUM.GenerateSeedPhrase {
val words12 = generatedWords12.mnemonicComponents.mapIndexed { index, s ->
MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem(index + 1, s)
}.toImmutableList()
@ -22,26 +27,35 @@ internal class GenerateSeedPhraseUiStateBuilder(
}.toImmutableList()
return MultiWalletSeedPhraseUM.GenerateSeedPhrase(
words24OptionSelected = false,
words = words12,
onWords24OptionSwitch = { switchType(words12, words24) },
option = option,
words = when (option) {
GeneratedWordsType.Words12 -> words12
GeneratedWordsType.Words24 -> words24
},
onOptionChange = {
switchType(
newType = it,
generatedWords12 = words12,
generatedWords24 = words24,
)
},
onContinueClick = onContinue,
)
}
private fun switchType(
newType: GeneratedWordsType,
generatedWords12: ImmutableList<MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem>,
generatedWords24: ImmutableList<MultiWalletSeedPhraseUM.GenerateSeedPhrase.MnemonicGridItem>,
) {
updateUiState { uiSt ->
changeWords24Option(uiSt.words24OptionSelected.not())
changeGeneratedWordsType(newType)
uiSt.copy(
words24OptionSelected = uiSt.words24OptionSelected.not(),
words = if (uiSt.words24OptionSelected) {
generatedWords12
} else {
generatedWords24
option = newType,
words = when (newType) {
GeneratedWordsType.Words12 -> generatedWords12
GeneratedWordsType.Words24 -> generatedWords24
},
)
}

View file

@ -20,6 +20,7 @@ import kotlinx.coroutines.launch
internal class ImportSeedPhraseUiStateBuilder(
private val modelScope: CoroutineScope,
private val mnemonicRepository: MnemonicRepository,
private val readyToImport: (Boolean) -> Unit,
private val updateUiState: ((MultiWalletSeedPhraseUM.Import) -> MultiWalletSeedPhraseUM.Import) -> Unit,
private val importWallet: (mnemonic: Mnemonic, passphrase: String?) -> Unit,
) {
@ -100,6 +101,8 @@ internal class ImportSeedPhraseUiStateBuilder(
}
private fun interceptWords(wordsField: TextFieldValue) {
readyToImport(false)
updateUiState {
it.copy(
createWalletEnabled = false,
@ -133,7 +136,9 @@ internal class ImportSeedPhraseUiStateBuilder(
createWalletEnabled = true,
)
}
readyToImport(true)
} catch (ex: TangemSdkError.MnemonicException) {
readyToImport(false)
val error = ex.mnemonicResult
if (error is MnemonicErrorResult.InvalidChecksum) {
updateUiState {

View file

@ -1,6 +1,7 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.builder
import androidx.compose.ui.text.input.TextFieldValue
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.GeneratedWordsType
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.SeedPhraseState
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.ui.state.MultiWalletSeedPhraseUM
import kotlinx.collections.immutable.toImmutableList
@ -93,10 +94,9 @@ internal class SeedPhraseCheckUiStateBuilder(
currentState.generatedWords12 ?: return false
currentState.generatedWords24 ?: return false
val wordList = if (currentState.words24Option) {
currentState.generatedWords24
} else {
currentState.generatedWords12
val wordList = when (currentState.generatedWordsType) {
GeneratedWordsType.Words12 -> currentState.generatedWords12
GeneratedWordsType.Words24 -> currentState.generatedWords24
}.mnemonicComponents
return wordList[shownIndex - 1] == word

View file

@ -19,6 +19,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.onboarding.v2.impl.R
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
@ -67,19 +68,24 @@ internal fun MultiWalletSeedPhraseWords(
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,
config = persistentListOf(GeneratedWordsType.Words12, GeneratedWordsType.Words24),
initialSelectedItem = state.option,
onClick = {
if (state.words24OptionSelected && it == 0 || state.words24OptionSelected.not() && it == 1) {
state.onWords24OptionSwitch()
when {
state.option == GeneratedWordsType.Words12 && it == GeneratedWordsType.Words24 -> {
state.onOptionChange(it)
}
state.option == GeneratedWordsType.Words24 && it == GeneratedWordsType.Words12 -> {
state.onOptionChange(it)
}
}
},
) {
Text(
text = pluralStringResourceSafe(
id = R.plurals.onboarding_seed_generate_words_count,
count = if (it == 0) 12 else 24,
if (it == 0) 12 else 24,
count = state.option.length,
state.option.length,
),
modifier = Modifier
.padding(vertical = TangemTheme.dimens.spacing10)
@ -110,8 +116,8 @@ private fun TitleBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, modifi
Text(
text = pluralStringResourceSafe(
id = R.plurals.onboarding_seed_generate_message_words_count,
count = if (state.words24OptionSelected.not()) 12 else 24,
if (state.words24OptionSelected.not()) 12 else 24,
count = state.option.length,
state.option.length,
),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,

View file

@ -4,6 +4,7 @@ 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 com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.GeneratedWordsType
import com.tangem.features.onboarding.v2.multiwallet.impl.common.ui.OnboardingDialogUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -20,9 +21,9 @@ internal sealed class MultiWalletSeedPhraseUM(
) : MultiWalletSeedPhraseUM(order = 0)
data class GenerateSeedPhrase(
val words24OptionSelected: Boolean = false,
val option: GeneratedWordsType = GeneratedWordsType.Words12,
val words: ImmutableList<MnemonicGridItem> = persistentListOf(),
val onWords24OptionSwitch: () -> Unit = {},
val onOptionChange: (GeneratedWordsType) -> Unit = {},
val onContinueClick: () -> Unit = {},
) : MultiWalletSeedPhraseUM(order = 1) {
data class MnemonicGridItem(