installer: add backup mnemonic step

This commit is contained in:
edouard 2023-02-10 13:18:22 +01:00
parent f8dcd1116d
commit 233f9b1886
5 changed files with 108 additions and 3 deletions

View File

@ -15,8 +15,8 @@ use crate::app::{config as gui_config, settings as gui_settings};
pub use message::Message;
use step::{
BackupDescriptor, DefineBitcoind, DefineDescriptor, Final, ImportDescriptor, ParticipateXpub,
RegisterDescriptor, Step, Welcome,
BackupDescriptor, BackupMnemonic, DefineBitcoind, DefineDescriptor, Final, ImportDescriptor,
ParticipateXpub, RegisterDescriptor, Step, Welcome,
};
pub struct Installer {
@ -91,6 +91,7 @@ impl Installer {
self.steps = vec![
Welcome::default().into(),
DefineDescriptor::new().into(),
BackupMnemonic::default().into(),
BackupDescriptor::default().into(),
RegisterDescriptor::default().into(),
DefineBitcoind::new().into(),
@ -103,6 +104,7 @@ impl Installer {
Welcome::default().into(),
ParticipateXpub::new().into(),
ImportDescriptor::new(false).into(),
BackupMnemonic::default().into(),
BackupDescriptor::default().into(),
RegisterDescriptor::default().into(),
DefineBitcoind::new().into(),
@ -165,11 +167,28 @@ impl Installer {
}
}
/// Some steps are skipped because of contextual choice of the user, this
/// code is giving a correct progress summary to the user.
fn progress(&self) -> (usize, usize) {
let mut current = self.current;
let mut total = 0;
for (i, step) in self.steps.iter().enumerate() {
if step.skip(&self.context) {
if i < self.current {
current -= 1;
}
} else {
total += 1
}
}
(current, total - 1)
}
pub fn view(&self) -> Element<Message> {
self.steps
.get(self.current)
.expect("There is always a step")
.view((self.current, self.steps.len() - 1))
.view(self.progress())
}
}

View File

@ -7,3 +7,4 @@ pub const DEFINE_DESCRIPTOR_SEQUENCE_TOOLTIP: &str =
pub const DEFINE_DESCRIPTOR_FINGERPRINT_TOOLTIP: &str =
"The alias is applied on all the keys derived from the same seed";
pub const REGISTER_DESCRIPTOR_HELP: &str = "To be used with the wallet, a device needs the descriptor. Registration on a device is not a substitute for backing up the descriptor.";
pub const MNEMONIC_HELP: &str = "A hot key generated on this computer was used for creating this wallet. It needs to be backed up. \n Keep it in a safe place. Never share it with anyone.";

View File

@ -0,0 +1,35 @@
use crate::installer::{context::Context, message::Message, step::Step, view};
use iced::{Command, Element};
#[derive(Default)]
pub struct BackupMnemonic {
words: [&'static str; 12],
done: bool,
}
impl From<BackupMnemonic> for Box<dyn Step> {
fn from(s: BackupMnemonic) -> Box<dyn Step> {
Box::new(s)
}
}
impl Step for BackupMnemonic {
fn load_context(&mut self, ctx: &Context) {
if let Some(signer) = &ctx.signer {
self.words = signer.mnemonic();
}
}
fn update(&mut self, message: Message) -> Command<Message> {
if let Message::UserActionDone(done) = message {
self.done = done;
}
Command::none()
}
fn skip(&self, ctx: &Context) -> bool {
ctx.signer.is_none()
}
fn view(&self, progress: (usize, usize)) -> Element<Message> {
view::backup_mnemonic(progress, &self.words, self.done)
}
}

View File

@ -1,8 +1,12 @@
mod descriptor;
mod mnemonic;
pub use descriptor::{
BackupDescriptor, DefineDescriptor, ImportDescriptor, ParticipateXpub, RegisterDescriptor,
};
pub use mnemonic::BackupMnemonic;
use std::path::PathBuf;
use std::str::FromStr;

View File

@ -1319,6 +1319,52 @@ fn hw_list_view(
.into()
}
pub fn backup_mnemonic<'a>(
progress: (usize, usize),
words: &'a [&'static str; 12],
done: bool,
) -> Element<'a, Message> {
layout(
progress,
Column::new()
.push(text("Backup your mnemonic").bold().size(50))
.push(text(prompt::MNEMONIC_HELP))
.push(
words
.iter()
.enumerate()
.fold(Column::new().spacing(5), |acc, (i, w)| {
acc.push(
Row::new()
.align_items(Alignment::End)
.push(
Container::new(text(format!("#{}", i + 1)).small())
.width(Length::Units(50)),
)
.push(text(*w).bold()),
)
}),
)
.push(Checkbox::new(
"I have backed up my mnemonic",
done,
Message::UserActionDone,
))
.push(if done {
button::primary(None, "Next")
.on_press(Message::Next)
.width(Length::Units(200))
} else {
button::primary(None, "Next").width(Length::Units(200))
})
.width(Length::Fill)
.height(Length::Fill)
.padding(100)
.spacing(50)
.align_items(Alignment::Center),
)
}
fn layout<'a>(
progress: (usize, usize),
content: impl Into<Element<'a, Message>>,