Merge #715: installer: Finalize installation and start automatically on final step
f771e674faccf150a5210b3abe829d443619c3e6 gui(installer): restrict clicking previous on final step (jp1ac4) 45f91216d5d0991d7aebde8d4c8bc99edaf5521a gui(installer): remove unused fields from final step (jp1ac4) 03c2bd76b8c6c1b721014afb37da7732ddfeb0cd gui(installer): install and start automatically on final step (jp1ac4) Pull request description: This is to resolve #679. The following changes have been made: - Change title of final step to "Finalize installation" - Install and load wallet automatically when reaching final step - Remove fields from `Final` step that are no longer used This is how the page looks when installing:  The following is only shown for ~1 sec once wallet has been installed and before loading wallet:  ACKs for top commit: edouardparis: ACK f771e674faccf150a5210b3abe829d443619c3e6 Tree-SHA512: b5360c77a13e4028331e4072246f1c897aa6fe61b0c8697b33d5c91ed460e55fe76b8808f4779db2b2f0322e27433e5dbb72fd0210cbf77f28a270bd82ea2558
This commit is contained in:
commit
52eabd6e07
@ -120,7 +120,6 @@ impl Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, message: Message) -> Command<Message> {
|
pub fn update(&mut self, message: Message) -> Command<Message> {
|
||||||
let hot_signer_fingerprint = self.signer.lock().unwrap().fingerprint();
|
|
||||||
match message {
|
match message {
|
||||||
Message::CreateWallet => {
|
Message::CreateWallet => {
|
||||||
self.steps = vec![
|
self.steps = vec![
|
||||||
@ -132,7 +131,7 @@ impl Installer {
|
|||||||
SelectBitcoindTypeStep::new().into(),
|
SelectBitcoindTypeStep::new().into(),
|
||||||
InternalBitcoindStep::new(&self.context.data_dir).into(),
|
InternalBitcoindStep::new(&self.context.data_dir).into(),
|
||||||
DefineBitcoind::new().into(),
|
DefineBitcoind::new().into(),
|
||||||
Final::new(hot_signer_fingerprint).into(),
|
Final::new().into(),
|
||||||
];
|
];
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
@ -147,7 +146,7 @@ impl Installer {
|
|||||||
SelectBitcoindTypeStep::new().into(),
|
SelectBitcoindTypeStep::new().into(),
|
||||||
InternalBitcoindStep::new(&self.context.data_dir).into(),
|
InternalBitcoindStep::new(&self.context.data_dir).into(),
|
||||||
DefineBitcoind::new().into(),
|
DefineBitcoind::new().into(),
|
||||||
Final::new(hot_signer_fingerprint).into(),
|
Final::new().into(),
|
||||||
];
|
];
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
@ -160,7 +159,7 @@ impl Installer {
|
|||||||
SelectBitcoindTypeStep::new().into(),
|
SelectBitcoindTypeStep::new().into(),
|
||||||
InternalBitcoindStep::new(&self.context.data_dir).into(),
|
InternalBitcoindStep::new(&self.context.data_dir).into(),
|
||||||
DefineBitcoind::new().into(),
|
DefineBitcoind::new().into(),
|
||||||
Final::new(hot_signer_fingerprint).into(),
|
Final::new().into(),
|
||||||
];
|
];
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,13 @@ pub use mnemonic::{BackupMnemonic, RecoverMnemonic};
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use iced::{Command, Subscription};
|
use iced::{Command, Subscription};
|
||||||
use liana::miniscript::bitcoin::bip32::Fingerprint;
|
|
||||||
|
|
||||||
use liana_ui::widget::*;
|
use liana_ui::widget::*;
|
||||||
|
|
||||||
use crate::installer::{context::Context, message::Message, view};
|
use crate::{
|
||||||
|
bitcoind::Bitcoind,
|
||||||
|
installer::{context::Context, message::Message, view},
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Step {
|
pub trait Step {
|
||||||
fn update(&mut self, _message: Message) -> Command<Message> {
|
fn update(&mut self, _message: Message) -> Command<Message> {
|
||||||
@ -60,42 +62,37 @@ impl From<Welcome> for Box<dyn Step> {
|
|||||||
|
|
||||||
pub struct Final {
|
pub struct Final {
|
||||||
generating: bool,
|
generating: bool,
|
||||||
context: Option<Context>,
|
internal_bitcoind: Option<Bitcoind>,
|
||||||
warning: Option<String>,
|
warning: Option<String>,
|
||||||
config_path: Option<PathBuf>,
|
config_path: Option<PathBuf>,
|
||||||
hot_signer_fingerprint: Fingerprint,
|
|
||||||
hot_signer_is_not_used: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Final {
|
impl Final {
|
||||||
pub fn new(hot_signer_fingerprint: Fingerprint) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
context: None,
|
internal_bitcoind: None,
|
||||||
generating: false,
|
generating: false,
|
||||||
warning: None,
|
warning: None,
|
||||||
config_path: None,
|
config_path: None,
|
||||||
hot_signer_fingerprint,
|
|
||||||
hot_signer_is_not_used: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Final {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Step for Final {
|
impl Step for Final {
|
||||||
fn load_context(&mut self, ctx: &Context) {
|
fn load_context(&mut self, ctx: &Context) {
|
||||||
self.context = Some(ctx.clone());
|
self.internal_bitcoind = ctx.internal_bitcoind.clone();
|
||||||
if let Some(signer) = &ctx.recovered_signer {
|
}
|
||||||
self.hot_signer_fingerprint = signer.fingerprint();
|
fn load(&self) -> Command<Message> {
|
||||||
self.hot_signer_is_not_used = false;
|
if !self.generating && self.config_path.is_none() {
|
||||||
} else if ctx
|
Command::perform(async {}, |_| Message::Install)
|
||||||
.descriptor
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.to_string()
|
|
||||||
.contains(&self.hot_signer_fingerprint.to_string())
|
|
||||||
{
|
|
||||||
self.hot_signer_is_not_used = false;
|
|
||||||
} else {
|
} else {
|
||||||
self.hot_signer_is_not_used = true;
|
Command::none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn update(&mut self, message: Message) -> Command<Message> {
|
fn update(&mut self, message: Message) -> Command<Message> {
|
||||||
@ -107,7 +104,13 @@ impl Step for Final {
|
|||||||
self.config_path = None;
|
self.config_path = None;
|
||||||
self.warning = Some(e.to_string());
|
self.warning = Some(e.to_string());
|
||||||
}
|
}
|
||||||
Ok(path) => self.config_path = Some(path),
|
Ok(path) => {
|
||||||
|
self.config_path = Some(path.clone());
|
||||||
|
let internal_bitcoind = self.internal_bitcoind.clone();
|
||||||
|
return Command::perform(async {}, move |_| {
|
||||||
|
Message::Exit(path.clone(), internal_bitcoind)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Install => {
|
Message::Install => {
|
||||||
@ -121,20 +124,11 @@ impl Step for Final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, progress: (usize, usize)) -> Element<Message> {
|
fn view(&self, progress: (usize, usize)) -> Element<Message> {
|
||||||
let ctx = self.context.as_ref().unwrap();
|
|
||||||
let desc = ctx.descriptor.as_ref().unwrap().to_string();
|
|
||||||
view::install(
|
view::install(
|
||||||
progress,
|
progress,
|
||||||
ctx,
|
|
||||||
desc,
|
|
||||||
self.generating,
|
self.generating,
|
||||||
self.config_path.as_ref(),
|
self.config_path.as_ref(),
|
||||||
self.warning.as_ref(),
|
self.warning.as_ref(),
|
||||||
if self.hot_signer_is_not_used {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(self.hot_signer_fingerprint)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@ use crate::{
|
|||||||
bitcoind::StartInternalBitcoindError,
|
bitcoind::StartInternalBitcoindError,
|
||||||
hw::HardwareWallet,
|
hw::HardwareWallet,
|
||||||
installer::{
|
installer::{
|
||||||
context::Context,
|
|
||||||
message::{self, Message},
|
message::{self, Message},
|
||||||
prompt,
|
prompt,
|
||||||
step::{DownloadState, InstallState},
|
step::{DownloadState, InstallState},
|
||||||
@ -303,7 +302,7 @@ pub fn define_descriptor<'a>(
|
|||||||
.push(Space::with_height(Length::Fixed(20.0)))
|
.push(Space::with_height(Length::Fixed(20.0)))
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
false,
|
false,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +422,7 @@ pub fn import_descriptor<'a>(
|
|||||||
.push_maybe(error.map(|e| card::error("Invalid descriptor", e.to_string())))
|
.push_maybe(error.map(|e| card::error("Invalid descriptor", e.to_string())))
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +630,7 @@ pub fn participate_xpub<'a>(
|
|||||||
})
|
})
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -723,7 +722,7 @@ pub fn register_descriptor<'a>(
|
|||||||
})
|
})
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,7 +790,7 @@ pub fn backup_descriptor<'a>(
|
|||||||
})
|
})
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,7 +877,7 @@ pub fn define_bitcoin<'a>(
|
|||||||
)
|
)
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,7 +971,7 @@ pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1092,163 +1091,37 @@ pub fn start_internal_bitcoind<'a>(
|
|||||||
|
|
||||||
pub fn install<'a>(
|
pub fn install<'a>(
|
||||||
progress: (usize, usize),
|
progress: (usize, usize),
|
||||||
context: &Context,
|
|
||||||
descriptor: String,
|
|
||||||
generating: bool,
|
generating: bool,
|
||||||
config_path: Option<&std::path::PathBuf>,
|
config_path: Option<&std::path::PathBuf>,
|
||||||
warning: Option<&'a String>,
|
warning: Option<&'a String>,
|
||||||
signer: Option<Fingerprint>,
|
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
|
let prev_msg = if !generating && warning.is_some() {
|
||||||
|
Some(Message::Previous)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
layout(
|
layout(
|
||||||
progress,
|
progress,
|
||||||
"Final step",
|
"Finalize installation",
|
||||||
Column::new()
|
Column::new()
|
||||||
.push(text(
|
|
||||||
"Check your information before finalizing the install process:",
|
|
||||||
))
|
|
||||||
.push(
|
|
||||||
Container::new(
|
|
||||||
Column::new()
|
|
||||||
.spacing(10)
|
|
||||||
.push(
|
|
||||||
card::simple(
|
|
||||||
Column::new()
|
|
||||||
.spacing(5)
|
|
||||||
.push(text("Descriptor:").small().bold())
|
|
||||||
.push(text(descriptor).small()),
|
|
||||||
)
|
|
||||||
.width(Length::Fill),
|
|
||||||
)
|
|
||||||
.push_maybe(if context.hws.is_empty() && signer.is_none() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(
|
|
||||||
card::simple(
|
|
||||||
Column::new()
|
|
||||||
.spacing(5)
|
|
||||||
.push(text("Registered signing devices:").small().bold())
|
|
||||||
.push_maybe(if context.hws.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(context.hws.iter().fold(
|
|
||||||
Column::new(),
|
|
||||||
|acc, hw| {
|
|
||||||
acc.push(
|
|
||||||
Row::new()
|
|
||||||
.spacing(5)
|
|
||||||
.push_maybe(
|
|
||||||
context.keys.iter().find_map(|k| {
|
|
||||||
if k.master_fingerprint == hw.1
|
|
||||||
{
|
|
||||||
Some(
|
|
||||||
text(k.name.clone())
|
|
||||||
.small()
|
|
||||||
.bold(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.push(
|
|
||||||
text(format!("#{}", hw.1)).small(),
|
|
||||||
)
|
|
||||||
.push(text(hw.0.to_string()).small()),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.push_maybe(signer.as_ref().map(|fingerprint| {
|
|
||||||
Row::new()
|
|
||||||
.spacing(5)
|
|
||||||
.push_maybe(context.keys.iter().find_map(|k| {
|
|
||||||
if k.master_fingerprint == *fingerprint {
|
|
||||||
Some(text(k.name.clone()).small().bold())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.push(text(format!("#{}", fingerprint)).small())
|
|
||||||
.push(text("This computer").small())
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.width(Length::Fill),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.push(
|
|
||||||
card::simple(
|
|
||||||
Column::new()
|
|
||||||
.push(text("Bitcoind:").small().bold())
|
|
||||||
.push(
|
|
||||||
Row::new()
|
|
||||||
.spacing(5)
|
|
||||||
.align_items(Alignment::Center)
|
|
||||||
.push(text("Cookie path:").small())
|
|
||||||
.push(
|
|
||||||
text(format!(
|
|
||||||
"{}",
|
|
||||||
context
|
|
||||||
.bitcoind_config
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.cookie_path
|
|
||||||
.to_string_lossy()
|
|
||||||
))
|
|
||||||
.small(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.push(
|
|
||||||
Row::new()
|
|
||||||
.spacing(5)
|
|
||||||
.align_items(Alignment::Center)
|
|
||||||
.push(text("Address:").small())
|
|
||||||
.push(
|
|
||||||
text(format!(
|
|
||||||
"{}",
|
|
||||||
context.bitcoind_config.as_ref().unwrap().addr
|
|
||||||
))
|
|
||||||
.small(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.width(Length::Fill),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.max_width(1000),
|
|
||||||
)
|
|
||||||
.push(Space::with_height(Length::Fixed(50.0)))
|
|
||||||
.push_maybe(warning.map(|e| card::invalid(text(e))))
|
.push_maybe(warning.map(|e| card::invalid(text(e))))
|
||||||
.push(if generating {
|
.push(if generating {
|
||||||
Container::new(button::primary(None, "Installing ...").width(Length::Fixed(200.0)))
|
Container::new(text("Installing..."))
|
||||||
} else if let Some(path) = config_path {
|
} else if config_path.is_some() {
|
||||||
Container::new(
|
Container::new(
|
||||||
Column::new()
|
Row::new()
|
||||||
.push(Container::new(text("Installed !")))
|
.spacing(10)
|
||||||
.push(Container::new(
|
|
||||||
button::primary(None, "Start")
|
|
||||||
.on_press(Message::Exit(
|
|
||||||
path.clone(),
|
|
||||||
context.internal_bitcoind.clone(),
|
|
||||||
))
|
|
||||||
.width(Length::Fixed(200.0)),
|
|
||||||
))
|
|
||||||
.align_items(Alignment::Center)
|
.align_items(Alignment::Center)
|
||||||
.spacing(20),
|
.push(icon::circle_check_icon().style(color::GREEN))
|
||||||
|
.push(text("Installed").style(color::GREEN)),
|
||||||
)
|
)
|
||||||
.padding(50)
|
|
||||||
.width(Length::Fill)
|
|
||||||
.center_x()
|
|
||||||
} else {
|
} else {
|
||||||
Container::new(
|
Container::new(Space::with_height(Length::Fixed(25.0)))
|
||||||
button::primary(None, "Finalize installation")
|
|
||||||
.on_press(Message::Install)
|
|
||||||
.width(Length::Fixed(200.0)),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
true,
|
true,
|
||||||
None,
|
prev_msg,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1758,7 +1631,7 @@ pub fn backup_mnemonic<'a>(
|
|||||||
})
|
})
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1861,7 +1734,7 @@ pub fn recover_mnemonic<'a>(
|
|||||||
})
|
})
|
||||||
.spacing(50),
|
.spacing(50),
|
||||||
true,
|
true,
|
||||||
None,
|
Some(Message::Previous),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1872,6 +1745,10 @@ fn layout<'a>(
|
|||||||
padding_left: bool,
|
padding_left: bool,
|
||||||
previous_message: Option<Message>,
|
previous_message: Option<Message>,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
|
let mut prev_button = button::transparent(Some(icon::previous_icon()), "Previous");
|
||||||
|
if let Some(msg) = previous_message {
|
||||||
|
prev_button = prev_button.on_press(msg);
|
||||||
|
}
|
||||||
Container::new(scrollable(
|
Container::new(scrollable(
|
||||||
Column::new()
|
Column::new()
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
@ -1880,12 +1757,9 @@ fn layout<'a>(
|
|||||||
Row::new()
|
Row::new()
|
||||||
.align_items(Alignment::Center)
|
.align_items(Alignment::Center)
|
||||||
.push(
|
.push(
|
||||||
Container::new(
|
Container::new(prev_button)
|
||||||
button::transparent(Some(icon::previous_icon()), "Previous")
|
.width(Length::FillPortion(2))
|
||||||
.on_press(previous_message.unwrap_or(Message::Previous)),
|
.center_x(),
|
||||||
)
|
|
||||||
.width(Length::FillPortion(2))
|
|
||||||
.center_x(),
|
|
||||||
)
|
)
|
||||||
.push(Container::new(h3(title)).width(Length::FillPortion(8)))
|
.push(Container::new(h3(title)).width(Length::FillPortion(8)))
|
||||||
.push(
|
.push(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user