Updated on 2026-08-14
This commit is contained in:
parent
4df89bb521
commit
cf5a7d68ad
16 changed files with 406 additions and 66 deletions
|
|
@ -407,7 +407,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
private fun navigateToInitialScreenIfNeeded(intentWhichStartedActivity: Intent?) {
|
private fun navigateToInitialScreenIfNeeded(intentWhichStartedActivity: Intent?) {
|
||||||
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
|
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
|
||||||
val isNotScannedBefore = store.state.globalState.scanResponse == null
|
val isNotScannedBefore = store.state.globalState.scanResponse == null
|
||||||
val isOnboardingServiceNotActive = store.state.globalState.onboardingState.onboardingStarted
|
val isOnboardingServiceNotActive = !store.state.globalState.onboardingState.onboardingStarted
|
||||||
|
|
||||||
when {
|
when {
|
||||||
!backStackIsEmpty && isNotScannedBefore && isOnboardingServiceNotActive -> {
|
!backStackIsEmpty && isNotScannedBefore && isOnboardingServiceNotActive -> {
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ class TangemSdkManager(
|
||||||
suspend fun importWallet(
|
suspend fun importWallet(
|
||||||
scanResponse: ScanResponse,
|
scanResponse: ScanResponse,
|
||||||
mnemonic: String,
|
mnemonic: String,
|
||||||
|
passphrase: String?,
|
||||||
shouldReset: Boolean,
|
shouldReset: Boolean,
|
||||||
): CompletionResult<CreateProductWalletTaskResponse> {
|
): CompletionResult<CreateProductWalletTaskResponse> {
|
||||||
val defaultMnemonic = try {
|
val defaultMnemonic = try {
|
||||||
|
|
@ -118,6 +119,7 @@ class TangemSdkManager(
|
||||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||||
mnemonic = defaultMnemonic,
|
mnemonic = defaultMnemonic,
|
||||||
|
passphrase = passphrase,
|
||||||
shouldReset = shouldReset,
|
shouldReset = shouldReset,
|
||||||
),
|
),
|
||||||
scanResponse.card.cardId,
|
scanResponse.card.cardId,
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ class CreateProductWalletTask(
|
||||||
private val cardTypesResolver: CardTypesResolver,
|
private val cardTypesResolver: CardTypesResolver,
|
||||||
private val derivationStyleProvider: DerivationStyleProvider,
|
private val derivationStyleProvider: DerivationStyleProvider,
|
||||||
private val mnemonic: Mnemonic? = null,
|
private val mnemonic: Mnemonic? = null,
|
||||||
|
private val passphrase: String? = null,
|
||||||
private val shouldReset: Boolean,
|
private val shouldReset: Boolean,
|
||||||
) : CardSessionRunnable<CreateProductWalletTaskResponse> {
|
) : CardSessionRunnable<CreateProductWalletTaskResponse> {
|
||||||
|
|
||||||
|
|
@ -82,7 +83,7 @@ class CreateProductWalletTask(
|
||||||
cardTypesResolver.isTangemTwins() ->
|
cardTypesResolver.isTangemTwins() ->
|
||||||
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
|
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
|
||||||
|
|
||||||
else -> CreateWalletTangemWallet(mnemonic, shouldReset, derivationStyleProvider, cardDto)
|
else -> CreateWalletTangemWallet(mnemonic, passphrase, shouldReset, derivationStyleProvider, cardDto)
|
||||||
}
|
}
|
||||||
commandProcessor.proceed(cardDto, session) {
|
commandProcessor.proceed(cardDto, session) {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
|
@ -142,6 +143,7 @@ private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesRes
|
||||||
*/
|
*/
|
||||||
private class CreateWalletTangemWallet(
|
private class CreateWalletTangemWallet(
|
||||||
private val mnemonic: Mnemonic?,
|
private val mnemonic: Mnemonic?,
|
||||||
|
private val passphrase: String?,
|
||||||
private val shouldReset: Boolean,
|
private val shouldReset: Boolean,
|
||||||
private val derivationStyleProvider: DerivationStyleProvider,
|
private val derivationStyleProvider: DerivationStyleProvider,
|
||||||
cardDTO: CardDTO,
|
cardDTO: CardDTO,
|
||||||
|
|
@ -170,7 +172,7 @@ private class CreateWalletTangemWallet(
|
||||||
session: CardSession,
|
session: CardSession,
|
||||||
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
CreateWalletsTask(cardConfig.mandatoryCurves, mnemonic).run(session) { result ->
|
CreateWalletsTask(cardConfig.mandatoryCurves, mnemonic, passphrase).run(session) { result ->
|
||||||
when (result) {
|
when (result) {
|
||||||
is CompletionResult.Success -> {
|
is CompletionResult.Success -> {
|
||||||
checkIfAllWalletsCreated(card, session, result.data, callback)
|
checkIfAllWalletsCreated(card, session, result.data, callback)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class CreateWalletsResponse(
|
||||||
class CreateWalletsTask(
|
class CreateWalletsTask(
|
||||||
private val curves: List<EllipticCurve>,
|
private val curves: List<EllipticCurve>,
|
||||||
private val mnemonic: Mnemonic? = null,
|
private val mnemonic: Mnemonic? = null,
|
||||||
|
private val passphrase: String?,
|
||||||
) : CardSessionRunnable<CreateWalletsResponse> {
|
) : CardSessionRunnable<CreateWalletsResponse> {
|
||||||
|
|
||||||
private val createdWalletsResponses = mutableListOf<CreateWalletResponse>()
|
private val createdWalletsResponses = mutableListOf<CreateWalletResponse>()
|
||||||
|
|
@ -41,7 +42,7 @@ class CreateWalletsTask(
|
||||||
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
|
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
val extendedPrivateKey = mnemonic?.let {
|
val extendedPrivateKey = mnemonic?.let {
|
||||||
AnyMasterKeyFactory(mnemonic = it, passphrase = "").makeMasterKey(curve)
|
AnyMasterKeyFactory(mnemonic = it, passphrase = passphrase ?: "").makeMasterKey(curve)
|
||||||
}
|
}
|
||||||
CreateWalletTask(curve, extendedPrivateKey).run(session) { result ->
|
CreateWalletTask(curve, extendedPrivateKey).run(session) { result ->
|
||||||
when (result) {
|
when (result) {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ sealed class OnboardingWallet2Action : OnboardingWalletAction() {
|
||||||
|
|
||||||
data class ImportWallet(
|
data class ImportWallet(
|
||||||
val mnemonicComponents: List<String>,
|
val mnemonicComponents: List<String>,
|
||||||
|
val passphrase: String?,
|
||||||
val seedPhraseSource: SeedPhraseSource,
|
val seedPhraseSource: SeedPhraseSource,
|
||||||
val callback: (CompletionResult<CreateWalletResponse>) -> Unit,
|
val callback: (CompletionResult<CreateWalletResponse>) -> Unit,
|
||||||
) : OnboardingWallet2Action()
|
) : OnboardingWallet2Action()
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,7 @@ private fun handleWallet2Action(action: OnboardingWallet2Action) {
|
||||||
val mediateResult = when (
|
val mediateResult = when (
|
||||||
val result = tangemSdkManager.importWallet(
|
val result = tangemSdkManager.importWallet(
|
||||||
scanResponse = scanResponse,
|
scanResponse = scanResponse,
|
||||||
|
passphrase = action.passphrase,
|
||||||
mnemonic = action.mnemonicComponents.joinToString(" "),
|
mnemonic = action.mnemonicComponents.joinToString(" "),
|
||||||
shouldReset = globalState.onboardingState.shouldResetOnCreate,
|
shouldReset = globalState.onboardingState.shouldResetOnCreate,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -523,10 +523,18 @@ class OnboardingWalletFragment :
|
||||||
|
|
||||||
override fun importWallet(
|
override fun importWallet(
|
||||||
mnemonicComponents: List<String>,
|
mnemonicComponents: List<String>,
|
||||||
|
passphrase: String?,
|
||||||
seedPhraseSource: SeedPhraseSource,
|
seedPhraseSource: SeedPhraseSource,
|
||||||
callback: (CompletionResult<CreateWalletResponse>) -> Unit,
|
callback: (CompletionResult<CreateWalletResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
store.dispatch(OnboardingWallet2Action.ImportWallet(mnemonicComponents, seedPhraseSource, callback))
|
store.dispatch(
|
||||||
|
OnboardingWallet2Action.ImportWallet(
|
||||||
|
mnemonicComponents,
|
||||||
|
passphrase,
|
||||||
|
seedPhraseSource,
|
||||||
|
callback,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allowScreenshots(allow: Boolean) {
|
override fun allowScreenshots(allow: Boolean) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.core.ui.components
|
package com.tangem.core.ui.components
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
|
@ -59,6 +60,40 @@ fun OutlineTextField(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OutlineTextFieldWithIcon(
|
||||||
|
value: TextFieldValue,
|
||||||
|
onValueChange: (TextFieldValue) -> Unit,
|
||||||
|
@DrawableRes iconResId: Int,
|
||||||
|
iconColor: Color,
|
||||||
|
onIconClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
label: String? = null,
|
||||||
|
placeholder: String? = null,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
isError: Boolean = false,
|
||||||
|
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||||
|
keyboardActions: KeyboardActions = KeyboardActions(),
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
) {
|
||||||
|
TangemTextFieldWithIcon(
|
||||||
|
modifier = modifier,
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
iconResId = iconResId,
|
||||||
|
iconColor = iconColor,
|
||||||
|
singleLine = true,
|
||||||
|
label = label,
|
||||||
|
placeholder = placeholder,
|
||||||
|
enabled = enabled,
|
||||||
|
isError = isError,
|
||||||
|
keyboardOptions = keyboardOptions,
|
||||||
|
keyboardActions = keyboardActions,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
onIconClick = onIconClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// region Defaults
|
// region Defaults
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -168,6 +203,84 @@ private fun TangemTextField(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongMethod")
|
||||||
|
@Composable
|
||||||
|
private fun TangemTextFieldWithIcon(
|
||||||
|
value: TextFieldValue,
|
||||||
|
singleLine: Boolean,
|
||||||
|
onValueChange: (TextFieldValue) -> Unit,
|
||||||
|
@DrawableRes iconResId: Int,
|
||||||
|
iconColor: Color,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
label: String? = null,
|
||||||
|
placeholder: String? = null,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
isError: Boolean = false,
|
||||||
|
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||||
|
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||||
|
keyboardActions: KeyboardActions = KeyboardActions(),
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
colors: TangemTextFieldColors = TangemTextFieldsDefault.defaultTextFieldColors,
|
||||||
|
size: TangemTextFieldSize = TangemTextFieldSize.Default,
|
||||||
|
onIconClick: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
Column(modifier = modifier) {
|
||||||
|
OutlinedTextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(IntrinsicSize.Min)
|
||||||
|
.heightIn(size.toHeightDp()),
|
||||||
|
value = value,
|
||||||
|
textStyle = TangemTheme.typography.body1,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
singleLine = singleLine,
|
||||||
|
enabled = enabled,
|
||||||
|
isError = isError,
|
||||||
|
visualTransformation = visualTransformation,
|
||||||
|
keyboardActions = keyboardActions,
|
||||||
|
keyboardOptions = keyboardOptions,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
shape = size.toShape(),
|
||||||
|
colors = colors,
|
||||||
|
label = {
|
||||||
|
if (!label.isNullOrEmpty()) {
|
||||||
|
Text(
|
||||||
|
text = label,
|
||||||
|
style = TangemTheme.typography.caption2,
|
||||||
|
color = colors.labelColor(
|
||||||
|
enabled = enabled,
|
||||||
|
error = isError,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
).value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
placeholder = {
|
||||||
|
if (!placeholder.isNullOrEmpty()) {
|
||||||
|
Text(
|
||||||
|
text = placeholder,
|
||||||
|
style = TangemTheme.typography.body1,
|
||||||
|
color = colors.placeholderColor(enabled = enabled).value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(
|
||||||
|
modifier = Modifier.size(32.dp),
|
||||||
|
onClick = onIconClick,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
painter = painterResource(id = iconResId),
|
||||||
|
tint = iconColor,
|
||||||
|
contentDescription = "Clear input",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum class TangemTextFieldSize {
|
private enum class TangemTextFieldSize {
|
||||||
Default,
|
Default,
|
||||||
}
|
}
|
||||||
|
|
@ -378,6 +491,16 @@ private fun OutlineTextFieldSample(modifier: Modifier = Modifier) {
|
||||||
caption = "Supporting text",
|
caption = "Supporting text",
|
||||||
)
|
)
|
||||||
Divider(modifier = Modifier.padding(vertical = 8.dp))
|
Divider(modifier = Modifier.padding(vertical = 8.dp))
|
||||||
|
OutlineTextFieldWithIcon(
|
||||||
|
value = TextFieldValue(),
|
||||||
|
onValueChange = { /* no-op */ },
|
||||||
|
iconResId = R.drawable.ic_alert_24,
|
||||||
|
iconColor = TangemTheme.colors.icon.informative,
|
||||||
|
label = "Default without value",
|
||||||
|
placeholder = "Placeholder",
|
||||||
|
onIconClick = {},
|
||||||
|
)
|
||||||
|
Divider(modifier = Modifier.padding(vertical = 8.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.tangem.feature.onboarding.presentation.wallet2.model
|
package com.tangem.feature.onboarding.presentation.wallet2.model
|
||||||
|
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||||
import com.tangem.feature.onboarding.domain.SeedPhraseError
|
import com.tangem.feature.onboarding.domain.SeedPhraseError
|
||||||
import com.tangem.feature.onboarding.domain.models.MnemonicType
|
import com.tangem.feature.onboarding.domain.models.MnemonicType
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
@ -64,11 +66,6 @@ enum class SegmentSeedType(val count: Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class MnemonicState(
|
|
||||||
val seedType: SegmentSeedType,
|
|
||||||
val mnemonicItems: PersistentList<MnemonicGridItem>,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class MnemonicGridItem(
|
data class MnemonicGridItem(
|
||||||
val index: Int,
|
val index: Int,
|
||||||
val mnemonic: String,
|
val mnemonic: String,
|
||||||
|
|
@ -82,14 +79,19 @@ data class CheckSeedPhraseState(
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ImportSeedPhraseState(
|
data class ImportSeedPhraseState(
|
||||||
val tvSeedPhrase: TextFieldState,
|
val fieldSeedPhrase: TextFieldState,
|
||||||
|
val fieldPassphrase: TextFieldState,
|
||||||
val onSuggestedPhraseClick: (Int) -> Unit,
|
val onSuggestedPhraseClick: (Int) -> Unit,
|
||||||
|
val onPassphraseInfoClick: () -> Unit,
|
||||||
val buttonCreateWallet: ButtonState,
|
val buttonCreateWallet: ButtonState,
|
||||||
val invalidWords: Set<String> = emptySet(),
|
val invalidWords: Set<String> = emptySet(),
|
||||||
val suggestionsList: ImmutableList<String> = persistentListOf(),
|
val suggestionsList: ImmutableList<String> = persistentListOf(),
|
||||||
val error: SeedPhraseError? = null,
|
val error: SeedPhraseError? = null,
|
||||||
|
val bottomSheetConfig: TangemBottomSheetConfig? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class ShowPassphraseInfoBottomSheetContent(val onOkClick: () -> Unit) : TangemBottomSheetConfigContent
|
||||||
|
|
||||||
data class TextFieldState(
|
data class TextFieldState(
|
||||||
val onTextFieldValueChanged: (TextFieldValue) -> Unit,
|
val onTextFieldValueChanged: (TextFieldValue) -> Unit,
|
||||||
val textFieldValue: TextFieldValue = TextFieldValue(),
|
val textFieldValue: TextFieldValue = TextFieldValue(),
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ data class CheckSeedPhraseUiAction(
|
||||||
|
|
||||||
data class ImportSeedPhraseUiAction(
|
data class ImportSeedPhraseUiAction(
|
||||||
val phraseTextFieldAction: TextFieldUiAction,
|
val phraseTextFieldAction: TextFieldUiAction,
|
||||||
|
val passTextFieldAction: TextFieldUiAction,
|
||||||
val suggestedPhraseClick: (Int) -> Unit,
|
val suggestedPhraseClick: (Int) -> Unit,
|
||||||
|
val onPassphraseInfoClick: () -> Unit,
|
||||||
val buttonCreateWalletClick: () -> Unit,
|
val buttonCreateWalletClick: () -> Unit,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
package com.tangem.feature.onboarding.presentation.wallet2.ui
|
package com.tangem.feature.onboarding.presentation.wallet2.ui
|
||||||
|
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.material.OutlinedTextField
|
import androidx.compose.material.OutlinedTextField
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -17,9 +20,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import com.tangem.core.ui.components.Notifier
|
import com.tangem.core.ui.components.*
|
||||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
|
||||||
import com.tangem.core.ui.components.TangemTextFieldsDefault
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.feature.onboarding.R
|
import com.tangem.feature.onboarding.R
|
||||||
import com.tangem.feature.onboarding.presentation.wallet2.model.ButtonState
|
import com.tangem.feature.onboarding.presentation.wallet2.model.ButtonState
|
||||||
|
|
@ -38,33 +39,31 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun ImportSeedPhraseScreen(state: ImportSeedPhraseState, modifier: Modifier = Modifier) {
|
fun ImportSeedPhraseScreen(state: ImportSeedPhraseState, modifier: Modifier = Modifier) {
|
||||||
Column(
|
val keyboard by keyboardAsState()
|
||||||
|
Box(
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
Box(
|
Column {
|
||||||
modifier = Modifier.weight(1f),
|
OnboardingDescriptionBlock(
|
||||||
) {
|
modifier = Modifier.padding(top = TangemTheme.dimens.size16),
|
||||||
Column {
|
) {
|
||||||
OnboardingDescriptionBlock(
|
DescriptionSubTitleText(text = stringResource(id = R.string.onboarding_seed_import_message))
|
||||||
modifier = Modifier.padding(top = TangemTheme.dimens.size16),
|
|
||||||
) {
|
|
||||||
DescriptionSubTitleText(text = stringResource(id = R.string.onboarding_seed_import_message))
|
|
||||||
}
|
|
||||||
PhraseBlock(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = TangemTheme.dimens.size62)
|
|
||||||
.padding(horizontal = TangemTheme.dimens.size16),
|
|
||||||
state = state,
|
|
||||||
)
|
|
||||||
SuggestionsBlock(
|
|
||||||
modifier = Modifier.padding(top = TangemTheme.dimens.size4),
|
|
||||||
suggestionsList = state.suggestionsList,
|
|
||||||
onClick = { index -> state.onSuggestedPhraseClick(index) },
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
PhraseBlock(
|
||||||
Box {
|
modifier = Modifier
|
||||||
|
.padding(top = TangemTheme.dimens.size62)
|
||||||
|
.padding(horizontal = TangemTheme.dimens.size16),
|
||||||
|
state = state,
|
||||||
|
)
|
||||||
|
|
||||||
|
PassphraseBlock(
|
||||||
|
modifier = Modifier.padding(horizontal = TangemTheme.dimens.size16),
|
||||||
|
passphraseField = state.fieldPassphrase,
|
||||||
|
onPassphraseInfoClick = state.onPassphraseInfoClick,
|
||||||
|
)
|
||||||
|
|
||||||
OnboardingActionBlock(
|
OnboardingActionBlock(
|
||||||
|
modifier = Modifier.padding(top = TangemTheme.dimens.size16),
|
||||||
firstActionContent = {
|
firstActionContent = {
|
||||||
PrimaryButtonIconEnd(
|
PrimaryButtonIconEnd(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -78,9 +77,41 @@ fun ImportSeedPhraseScreen(state: ImportSeedPhraseState, modifier: Modifier = Mo
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keyboard is Keyboard.Opened) {
|
||||||
|
SuggestionsBlock(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.imePadding(),
|
||||||
|
suggestionsList = state.suggestionsList,
|
||||||
|
onClick = { index -> state.onSuggestedPhraseClick(index) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.bottomSheetConfig != null) {
|
||||||
|
PassphraseInfoBottomSheet(config = state.bottomSheetConfig)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PassphraseBlock(
|
||||||
|
passphraseField: TextFieldState,
|
||||||
|
onPassphraseInfoClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
OutlineTextFieldWithIcon(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
value = passphraseField.textFieldValue,
|
||||||
|
onValueChange = passphraseField.onTextFieldValueChanged,
|
||||||
|
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 = onPassphraseInfoClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun PhraseBlock(state: ImportSeedPhraseState, modifier: Modifier = Modifier) {
|
private fun PhraseBlock(state: ImportSeedPhraseState, modifier: Modifier = Modifier) {
|
||||||
// TODO: replace by TextReference
|
// TODO: replace by TextReference
|
||||||
|
|
@ -93,8 +124,8 @@ private fun PhraseBlock(state: ImportSeedPhraseState, modifier: Modifier = Modif
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(TangemTheme.dimens.size142),
|
.height(TangemTheme.dimens.size142),
|
||||||
value = state.tvSeedPhrase.textFieldValue,
|
value = state.fieldSeedPhrase.textFieldValue,
|
||||||
onValueChange = state.tvSeedPhrase.onTextFieldValueChanged,
|
onValueChange = state.fieldSeedPhrase.onTextFieldValueChanged,
|
||||||
textStyle = TangemTheme.typography.body1,
|
textStyle = TangemTheme.typography.body1,
|
||||||
singleLine = false,
|
singleLine = false,
|
||||||
visualTransformation = InvalidWordsColorTransformation(
|
visualTransformation = InvalidWordsColorTransformation(
|
||||||
|
|
@ -131,12 +162,12 @@ private fun SuggestionsBlock(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
|
modifier = modifier,
|
||||||
enter = fadeIn() + slideIn(initialOffset = { IntOffset(x = 200, y = 0) }),
|
enter = fadeIn() + slideIn(initialOffset = { IntOffset(x = 200, y = 0) }),
|
||||||
exit = slideOut(targetOffset = { IntOffset(x = -200, y = 0) }) + fadeOut(),
|
exit = slideOut(targetOffset = { IntOffset(x = -200, y = 0) }) + fadeOut(),
|
||||||
visible = suggestionsList.isNotEmpty(),
|
visible = suggestionsList.isNotEmpty(),
|
||||||
) {
|
) {
|
||||||
LazyRow(
|
LazyRow(
|
||||||
modifier = modifier,
|
|
||||||
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.size16),
|
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.size16),
|
||||||
) {
|
) {
|
||||||
items(suggestionsList.size) { index ->
|
items(suggestionsList.size) { index ->
|
||||||
|
|
@ -160,7 +191,7 @@ private fun SuggestionButton(text: String, onClick: () -> Unit, modifier: Modifi
|
||||||
Box(modifier = modifier.clickable(onClick = onClick)) {
|
Box(modifier = modifier.clickable(onClick = onClick)) {
|
||||||
Notifier(
|
Notifier(
|
||||||
text = text,
|
text = text,
|
||||||
backgroundColor = TangemTheme.colors.background.action,
|
backgroundColor = TangemTheme.colors.icon.primary1,
|
||||||
textColor = TangemTheme.colors.text.primary2,
|
textColor = TangemTheme.colors.text.primary2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -204,19 +235,23 @@ private fun ImportSeedPhraseScreenPreview_Light(
|
||||||
@PreviewParameter(SuggestionsPreviewParamsProvider::class) suggestions: ImmutableList<String>,
|
@PreviewParameter(SuggestionsPreviewParamsProvider::class) suggestions: ImmutableList<String>,
|
||||||
) {
|
) {
|
||||||
TangemTheme(isDark = false) {
|
TangemTheme(isDark = false) {
|
||||||
ImportSeedPhraseScreen(
|
Box(modifier = Modifier.background(TangemTheme.colors.background.primary)) {
|
||||||
ImportSeedPhraseState(
|
ImportSeedPhraseScreen(
|
||||||
tvSeedPhrase = TextFieldState(onTextFieldValueChanged = {}),
|
ImportSeedPhraseState(
|
||||||
onSuggestedPhraseClick = {},
|
fieldSeedPhrase = TextFieldState(onTextFieldValueChanged = {}),
|
||||||
buttonCreateWallet = ButtonState(
|
fieldPassphrase = TextFieldState(onTextFieldValueChanged = {}),
|
||||||
enabled = true,
|
onSuggestedPhraseClick = {},
|
||||||
isClickable = true,
|
onPassphraseInfoClick = {},
|
||||||
showProgress = false,
|
buttonCreateWallet = ButtonState(
|
||||||
onClick = {},
|
enabled = true,
|
||||||
|
isClickable = true,
|
||||||
|
showProgress = false,
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
suggestionsList = suggestions,
|
||||||
),
|
),
|
||||||
suggestionsList = suggestions,
|
)
|
||||||
),
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
package com.tangem.feature.onboarding.presentation.wallet2.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.material.Icon
|
||||||
|
import androidx.compose.material.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.res.TangemTheme
|
||||||
|
import com.tangem.feature.onboarding.R
|
||||||
|
import com.tangem.feature.onboarding.presentation.wallet2.model.ShowPassphraseInfoBottomSheetContent
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PassphraseInfoBottomSheet(config: TangemBottomSheetConfig) {
|
||||||
|
TangemBottomSheet(
|
||||||
|
config = config,
|
||||||
|
containerColor = TangemTheme.colors.background.primary,
|
||||||
|
) { content: ShowPassphraseInfoBottomSheetContent ->
|
||||||
|
PassphraseInfoBottomSheetContent(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PassphraseInfoBottomSheetContent(content: ShowPassphraseInfoBottomSheetContent) {
|
||||||
|
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 = content.onOkClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun PassphraseInfoBottomSheetContentPreview() {
|
||||||
|
TangemTheme {
|
||||||
|
PassphraseInfoBottomSheetContent(ShowPassphraseInfoBottomSheetContent { })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,11 @@ package com.tangem.feature.onboarding.presentation.wallet2.ui.stateBuiders
|
||||||
|
|
||||||
import androidx.compose.ui.text.TextRange
|
import androidx.compose.ui.text.TextRange
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
import com.tangem.feature.onboarding.domain.InsertSuggestionResult
|
import com.tangem.feature.onboarding.domain.InsertSuggestionResult
|
||||||
import com.tangem.feature.onboarding.domain.SeedPhraseError
|
import com.tangem.feature.onboarding.domain.SeedPhraseError
|
||||||
import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState
|
import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState
|
||||||
|
import com.tangem.feature.onboarding.presentation.wallet2.model.ShowPassphraseInfoBottomSheetContent
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -12,12 +14,23 @@ import kotlinx.collections.immutable.ImmutableList
|
||||||
*/
|
*/
|
||||||
class ImportSeedPhraseStateBuilder {
|
class ImportSeedPhraseStateBuilder {
|
||||||
|
|
||||||
fun updateTextField(
|
fun updateSeedPhraseTextField(
|
||||||
uiState: OnboardingSeedPhraseState,
|
uiState: OnboardingSeedPhraseState,
|
||||||
textFieldValue: TextFieldValue,
|
textFieldValue: TextFieldValue,
|
||||||
): OnboardingSeedPhraseState = uiState.copy(
|
): OnboardingSeedPhraseState = uiState.copy(
|
||||||
importSeedPhraseState = uiState.importSeedPhraseState.copy(
|
importSeedPhraseState = uiState.importSeedPhraseState.copy(
|
||||||
tvSeedPhrase = uiState.importSeedPhraseState.tvSeedPhrase.copy(
|
fieldSeedPhrase = uiState.importSeedPhraseState.fieldSeedPhrase.copy(
|
||||||
|
textFieldValue = textFieldValue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
fun updatePassPhraseTextField(
|
||||||
|
uiState: OnboardingSeedPhraseState,
|
||||||
|
textFieldValue: TextFieldValue,
|
||||||
|
): OnboardingSeedPhraseState = uiState.copy(
|
||||||
|
importSeedPhraseState = uiState.importSeedPhraseState.copy(
|
||||||
|
fieldPassphrase = uiState.importSeedPhraseState.fieldPassphrase.copy(
|
||||||
textFieldValue = textFieldValue,
|
textFieldValue = textFieldValue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -49,15 +62,40 @@ class ImportSeedPhraseStateBuilder {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun showPassphraseInfoBottomSheet(
|
||||||
|
uiState: OnboardingSeedPhraseState,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
): OnboardingSeedPhraseState {
|
||||||
|
return uiState.copy(
|
||||||
|
importSeedPhraseState = uiState.importSeedPhraseState.copy(
|
||||||
|
bottomSheetConfig = TangemBottomSheetConfig(
|
||||||
|
isShow = true,
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
content = ShowPassphraseInfoBottomSheetContent(onDismiss),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dismissPassphraseBottomSheet(uiState: OnboardingSeedPhraseState): OnboardingSeedPhraseState {
|
||||||
|
return uiState.copy(
|
||||||
|
importSeedPhraseState = uiState.importSeedPhraseState.copy(
|
||||||
|
bottomSheetConfig = uiState.importSeedPhraseState.bottomSheetConfig?.copy(
|
||||||
|
isShow = false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun insertSuggestionWord(
|
fun insertSuggestionWord(
|
||||||
uiState: OnboardingSeedPhraseState,
|
uiState: OnboardingSeedPhraseState,
|
||||||
insertResult: InsertSuggestionResult,
|
insertResult: InsertSuggestionResult,
|
||||||
): OnboardingSeedPhraseState {
|
): OnboardingSeedPhraseState {
|
||||||
val newTextFieldValue = uiState.importSeedPhraseState.tvSeedPhrase.textFieldValue.copy(
|
val newTextFieldValue = uiState.importSeedPhraseState.fieldSeedPhrase.textFieldValue.copy(
|
||||||
text = insertResult.text,
|
text = insertResult.text,
|
||||||
selection = TextRange(insertResult.cursorPosition, insertResult.cursorPosition),
|
selection = TextRange(insertResult.cursorPosition, insertResult.cursorPosition),
|
||||||
)
|
)
|
||||||
return updateTextField(uiState, newTextFieldValue)
|
return updateSeedPhraseTextField(uiState, newTextFieldValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateError(uiState: OnboardingSeedPhraseState, error: SeedPhraseError?): OnboardingSeedPhraseState {
|
fun updateError(uiState: OnboardingSeedPhraseState, error: SeedPhraseError?): OnboardingSeedPhraseState {
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,16 @@ class StateBuilder(
|
||||||
|
|
||||||
private fun getInitialImportSeedPhraseState(): ImportSeedPhraseState {
|
private fun getInitialImportSeedPhraseState(): ImportSeedPhraseState {
|
||||||
return ImportSeedPhraseState(
|
return ImportSeedPhraseState(
|
||||||
tvSeedPhrase = TextFieldState(
|
fieldSeedPhrase = TextFieldState(
|
||||||
onTextFieldValueChanged = uiActions.importSeedPhraseActions.phraseTextFieldAction.onTextFieldChanged,
|
onTextFieldValueChanged = uiActions.importSeedPhraseActions.phraseTextFieldAction.onTextFieldChanged,
|
||||||
onFocusChanged = uiActions.importSeedPhraseActions.phraseTextFieldAction.onFocusChanged,
|
onFocusChanged = uiActions.importSeedPhraseActions.phraseTextFieldAction.onFocusChanged,
|
||||||
),
|
),
|
||||||
|
fieldPassphrase = TextFieldState(
|
||||||
|
onTextFieldValueChanged = uiActions.importSeedPhraseActions.passTextFieldAction.onTextFieldChanged,
|
||||||
|
onFocusChanged = uiActions.importSeedPhraseActions.passTextFieldAction.onFocusChanged,
|
||||||
|
),
|
||||||
onSuggestedPhraseClick = uiActions.importSeedPhraseActions.suggestedPhraseClick,
|
onSuggestedPhraseClick = uiActions.importSeedPhraseActions.suggestedPhraseClick,
|
||||||
|
onPassphraseInfoClick = uiActions.importSeedPhraseActions.onPassphraseInfoClick,
|
||||||
buttonCreateWallet = ButtonState(
|
buttonCreateWallet = ButtonState(
|
||||||
enabled = false,
|
enabled = false,
|
||||||
onClick = uiActions.importSeedPhraseActions.buttonCreateWalletClick,
|
onClick = uiActions.importSeedPhraseActions.buttonCreateWalletClick,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ interface SeedPhraseMediator {
|
||||||
fun createWallet(callback: (CompletionResult<CreateWalletResponse>) -> Unit)
|
fun createWallet(callback: (CompletionResult<CreateWalletResponse>) -> Unit)
|
||||||
fun importWallet(
|
fun importWallet(
|
||||||
mnemonicComponents: List<String>,
|
mnemonicComponents: List<String>,
|
||||||
|
passphrase: String?,
|
||||||
seedPhraseSource: SeedPhraseSource,
|
seedPhraseSource: SeedPhraseSource,
|
||||||
callback: (CompletionResult<CreateWalletResponse>) -> Unit,
|
callback: (CompletionResult<CreateWalletResponse>) -> Unit,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
|
|
||||||
private var generatedMnemonicComponents: Map<MnemonicType, List<String>> = emptyMap()
|
private var generatedMnemonicComponents: Map<MnemonicType, List<String>> = emptyMap()
|
||||||
private var importedMnemonicComponents: List<String>? = null
|
private var importedMnemonicComponents: List<String>? = null
|
||||||
|
private var importedPassphrase: String? = null
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
textFieldsDebouncers.forEach { entry -> entry.value.release() }
|
textFieldsDebouncers.forEach { entry -> entry.value.release() }
|
||||||
|
|
@ -143,7 +144,7 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
buttonCreateWalletClick = {
|
buttonCreateWalletClick = {
|
||||||
val mnemonicComponents =
|
val mnemonicComponents =
|
||||||
generatedMnemonicComponents[selectedMnemonicType] ?: return@CheckSeedPhraseUiAction
|
generatedMnemonicComponents[selectedMnemonicType] ?: return@CheckSeedPhraseUiAction
|
||||||
buttonImportWalletClick(mnemonicComponents, SeedPhraseSource.GENERATED)
|
buttonImportWalletClick(mnemonicComponents, null, SeedPhraseSource.GENERATED)
|
||||||
},
|
},
|
||||||
secondTextFieldAction = TextFieldUiAction(
|
secondTextFieldAction = TextFieldUiAction(
|
||||||
onTextFieldChanged = { value -> onTextFieldChanged(SeedPhraseField.Second, value) },
|
onTextFieldChanged = { value -> onTextFieldChanged(SeedPhraseField.Second, value) },
|
||||||
|
|
@ -159,10 +160,14 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
phraseTextFieldAction = TextFieldUiAction(
|
phraseTextFieldAction = TextFieldUiAction(
|
||||||
onTextFieldChanged = { value -> onSeedPhraseTextFieldChanged(value) },
|
onTextFieldChanged = { value -> onSeedPhraseTextFieldChanged(value) },
|
||||||
),
|
),
|
||||||
|
passTextFieldAction = TextFieldUiAction(
|
||||||
|
onTextFieldChanged = { value -> onPassPhraseTextFieldChanged(value) },
|
||||||
|
),
|
||||||
suggestedPhraseClick = ::buttonSuggestedPhraseClick,
|
suggestedPhraseClick = ::buttonSuggestedPhraseClick,
|
||||||
|
onPassphraseInfoClick = ::buttonPassphraseInfoClick,
|
||||||
buttonCreateWalletClick = {
|
buttonCreateWalletClick = {
|
||||||
analyticsEventHandler.send(SeedPhraseEvents.ButtonImport)
|
analyticsEventHandler.send(SeedPhraseEvents.ButtonImport)
|
||||||
buttonImportWalletClick(importedMnemonicComponents, SeedPhraseSource.IMPORTED)
|
buttonImportWalletClick(importedMnemonicComponents, importedPassphrase, SeedPhraseSource.IMPORTED)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
menuChatClick = ::menuChatClick,
|
menuChatClick = ::menuChatClick,
|
||||||
|
|
@ -208,13 +213,13 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
|
|
||||||
// region ImportSeedPhrase
|
// region ImportSeedPhrase
|
||||||
private fun onSeedPhraseTextFieldChanged(textFieldValue: TextFieldValue) {
|
private fun onSeedPhraseTextFieldChanged(textFieldValue: TextFieldValue) {
|
||||||
val oldTextFieldValue = uiState.importSeedPhraseState.tvSeedPhrase.textFieldValue
|
val oldTextFieldValue = uiState.importSeedPhraseState.fieldSeedPhrase.textFieldValue
|
||||||
val isSameText = textFieldValue.text == oldTextFieldValue.text
|
val isSameText = textFieldValue.text == oldTextFieldValue.text
|
||||||
val isCursorMoved = textFieldValue.selection != oldTextFieldValue.selection
|
val isCursorMoved = textFieldValue.selection != oldTextFieldValue.selection
|
||||||
|
|
||||||
uiState = uiBuilder.importSeedPhrase.updateTextField(uiState, textFieldValue)
|
uiState = uiBuilder.importSeedPhrase.updateSeedPhraseTextField(uiState, textFieldValue)
|
||||||
|
|
||||||
val fieldState = uiState.importSeedPhraseState.tvSeedPhrase
|
val fieldState = uiState.importSeedPhraseState.fieldSeedPhrase
|
||||||
val inputMnemonic = fieldState.textFieldValue.text
|
val inputMnemonic = fieldState.textFieldValue.text
|
||||||
|
|
||||||
val debouncer = createOrGetDebouncer(MNEMONIC_DEBOUNCER)
|
val debouncer = createOrGetDebouncer(MNEMONIC_DEBOUNCER)
|
||||||
|
|
@ -236,6 +241,11 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onPassPhraseTextFieldChanged(textFieldValue: TextFieldValue) {
|
||||||
|
importedPassphrase = textFieldValue.text
|
||||||
|
uiState = uiBuilder.importSeedPhrase.updatePassPhraseTextField(uiState, textFieldValue)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun validateMnemonic(inputMnemonic: String) {
|
private suspend fun validateMnemonic(inputMnemonic: String) {
|
||||||
if (inputMnemonic.isEmpty() && uiState.importSeedPhraseState.error != null) {
|
if (inputMnemonic.isEmpty() && uiState.importSeedPhraseState.error != null) {
|
||||||
val mediateState = uiBuilder.importSeedPhrase.updateCreateWalletButton(uiState, enabled = false)
|
val mediateState = uiBuilder.importSeedPhrase.updateCreateWalletButton(uiState, enabled = false)
|
||||||
|
|
@ -284,11 +294,15 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buttonImportWalletClick(mnemonicComponents: List<String>?, seedPhraseSource: SeedPhraseSource) {
|
private fun buttonImportWalletClick(
|
||||||
|
mnemonicComponents: List<String>?,
|
||||||
|
passphrase: String?,
|
||||||
|
seedPhraseSource: SeedPhraseSource,
|
||||||
|
) {
|
||||||
mnemonicComponents ?: return
|
mnemonicComponents ?: return
|
||||||
|
|
||||||
viewModelScope.launch(dispatchers.io) {
|
viewModelScope.launch(dispatchers.io) {
|
||||||
mediator.importWallet(mnemonicComponents, seedPhraseSource, ::handleWalletCreationResult)
|
mediator.importWallet(mnemonicComponents, passphrase, seedPhraseSource, ::handleWalletCreationResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,7 +405,7 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
|
|
||||||
private fun buttonSuggestedPhraseClick(suggestionIndex: Int) {
|
private fun buttonSuggestedPhraseClick(suggestionIndex: Int) {
|
||||||
launchSingle {
|
launchSingle {
|
||||||
val textFieldValue = uiState.importSeedPhraseState.tvSeedPhrase.textFieldValue
|
val textFieldValue = uiState.importSeedPhraseState.fieldSeedPhrase.textFieldValue
|
||||||
val word = uiState.importSeedPhraseState.suggestionsList[suggestionIndex]
|
val word = uiState.importSeedPhraseState.suggestionsList[suggestionIndex]
|
||||||
val cursorPosition = textFieldValue.selection.end
|
val cursorPosition = textFieldValue.selection.end
|
||||||
|
|
||||||
|
|
@ -406,6 +420,22 @@ class SeedPhraseViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buttonPassphraseInfoClick() {
|
||||||
|
launchSingle {
|
||||||
|
updateUi {
|
||||||
|
uiBuilder.importSeedPhrase.showPassphraseInfoBottomSheet(uiState) {
|
||||||
|
dismissPassphraseBottomSheet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dismissPassphraseBottomSheet() {
|
||||||
|
launchSingle {
|
||||||
|
updateUi { uiBuilder.importSeedPhrase.dismissPassphraseBottomSheet(uiState) }
|
||||||
|
}
|
||||||
|
}
|
||||||
// endregion ButtonClickHandlers
|
// endregion ButtonClickHandlers
|
||||||
|
|
||||||
// region Utils
|
// region Utils
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue