demo: add recover from mnemonic dialog

This commit is contained in:
Oscar Mira 2024-03-04 03:20:57 +01:00
parent 8febbd1543
commit 4cf0059739
2 changed files with 62 additions and 0 deletions

View File

@ -12,7 +12,9 @@ import im.molly.monero.demo.data.RemoteNodeRepository
import im.molly.monero.demo.data.WalletRepository import im.molly.monero.demo.data.WalletRepository
import im.molly.monero.demo.data.model.DefaultMoneroNetwork import im.molly.monero.demo.data.model.DefaultMoneroNetwork
import im.molly.monero.demo.data.model.RemoteNode import im.molly.monero.demo.data.model.RemoteNode
import im.molly.monero.mnemonics.MoneroMnemonic
import im.molly.monero.util.parseHex import im.molly.monero.util.parseHex
import im.molly.monero.util.toHex
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
@ -82,6 +84,16 @@ class AddWalletViewModel(
this.secretSpendKeyHex = value this.secretSpendKeyHex = value
} }
fun recoverFromMnemonic(words: String): Boolean {
MoneroMnemonic.recoverEntropy(words)?.use { mnemonicCode ->
val secretKey = SecretKey(mnemonicCode.entropy)
secretSpendKeyHex = secretKey.bytes.toHex()
secretKey.destroy()
return true
}
return false
}
fun updateCreationDate(value: String) { fun updateCreationDate(value: String) {
this.creationDate = value this.creationDate = value
} }

View File

@ -1,5 +1,6 @@
package im.molly.monero.demo.ui package im.molly.monero.demo.ui
import android.widget.Toast
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
@ -8,6 +9,7 @@ import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment 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.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -84,6 +86,8 @@ fun AddWalletSecondStepRoute(
onNavigateToHome: () -> Unit, onNavigateToHome: () -> Unit,
viewModel: AddWalletViewModel = viewModel(), viewModel: AddWalletViewModel = viewModel(),
) { ) {
val context = LocalContext.current
val remoteNodes by viewModel.currentRemoteNodes.collectAsStateWithLifecycle() val remoteNodes by viewModel.currentRemoteNodes.collectAsStateWithLifecycle()
SecondStepScreen( SecondStepScreen(
@ -109,6 +113,12 @@ fun AddWalletSecondStepRoute(
onWalletNameChanged = { name -> viewModel.updateWalletName(name) }, onWalletNameChanged = { name -> viewModel.updateWalletName(name) },
onNetworkChanged = { network -> viewModel.toggleSelectedNetwork(network) }, onNetworkChanged = { network -> viewModel.toggleSelectedNetwork(network) },
onSecretSpendKeyHexChanged = { value -> viewModel.updateSecretSpendKeyHex(value) }, onSecretSpendKeyHexChanged = { value -> viewModel.updateSecretSpendKeyHex(value) },
onRecoverFromMnemonic = { words ->
val success = viewModel.recoverFromMnemonic(words)
if (!success) {
Toast.makeText(context, "Invalid seed", Toast.LENGTH_LONG).show()
}
},
onCreationDateChanged = { value -> viewModel.updateCreationDate(value) }, onCreationDateChanged = { value -> viewModel.updateCreationDate(value) },
onRestoreHeightChanged = { value -> viewModel.updateRestoreHeight(value) }, onRestoreHeightChanged = { value -> viewModel.updateRestoreHeight(value) },
remoteNodes = remoteNodes, remoteNodes = remoteNodes,
@ -134,12 +144,14 @@ private fun SecondStepScreen(
onWalletNameChanged: (String) -> Unit = {}, onWalletNameChanged: (String) -> Unit = {},
onNetworkChanged: (MoneroNetwork) -> Unit = {}, onNetworkChanged: (MoneroNetwork) -> Unit = {},
onSecretSpendKeyHexChanged: (String) -> Unit = {}, onSecretSpendKeyHexChanged: (String) -> Unit = {},
onRecoverFromMnemonic: (String) -> Unit = {},
onCreationDateChanged: (String) -> Unit = {}, onCreationDateChanged: (String) -> Unit = {},
onRestoreHeightChanged: (String) -> Unit = {}, onRestoreHeightChanged: (String) -> Unit = {},
remoteNodes: List<RemoteNode>, remoteNodes: List<RemoteNode>,
selectedRemoteNodeIds: MutableMap<Long?, Boolean> = mutableMapOf(), selectedRemoteNodeIds: MutableMap<Long?, Boolean> = mutableMapOf(),
) { ) {
var showOffLineConfirmationDialog by remember { mutableStateOf(false) } var showOffLineConfirmationDialog by remember { mutableStateOf(false) }
var showMnemonicDialog by remember { mutableStateOf(false) }
Scaffold(topBar = { Scaffold(topBar = {
Toolbar( Toolbar(
@ -205,6 +217,13 @@ private fun SecondStepScreen(
.fillMaxWidth() .fillMaxWidth()
.padding(start = 16.dp, end = 16.dp), .padding(start = 16.dp, end = 16.dp),
) )
TextButton(
onClick = { showMnemonicDialog = true },
modifier = Modifier
.padding(start = 16.dp),
) {
Text("Recover from 25-word mnemonic")
}
Text( Text(
text = "Synchronization", text = "Synchronization",
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
@ -257,6 +276,37 @@ private fun SecondStepScreen(
} }
} }
if (showMnemonicDialog) {
var words by remember { mutableStateOf("") }
AlertDialog(
onDismissRequest = { showMnemonicDialog = false },
title = { Text("Enter your recovery phrase") },
text = {
OutlinedTextField(
value = words,
onValueChange = { words = it },
singleLine = true,
)
},
confirmButton = {
TextButton(
onClick = {
onRecoverFromMnemonic(words)
showMnemonicDialog = false
},
enabled = words.isNotEmpty(),
) {
Text("Confirm")
}
},
dismissButton = {
TextButton(onClick = { showMnemonicDialog = false }) {
Text("Cancel")
}
}
)
}
if (showOffLineConfirmationDialog) { if (showOffLineConfirmationDialog) {
AlertDialog(onDismissRequest = { showOffLineConfirmationDialog = false }, title = { AlertDialog(onDismissRequest = { showOffLineConfirmationDialog = false }, title = {
Text("No remote nodes selected") Text("No remote nodes selected")