diff --git a/gui/src/installer/prompt.rs b/gui/src/installer/prompt.rs index 1cdc9e1c..c84211c9 100644 --- a/gui/src/installer/prompt.rs +++ b/gui/src/installer/prompt.rs @@ -1,2 +1,2 @@ -pub const BACKUP_DESCRIPTOR_MESSAGE: &str = "The descriptor is necessary to recover your funds.\nThe backup of your key (via mnemonics, sometimes called 'seed words') is not enough.\nPlease make sure you have backed up both your private key and your descriptor."; +pub const BACKUP_DESCRIPTOR_MESSAGE: &str = "The descriptor is necessary to recover your funds. The backup of your key (via mnemonics, sometimes called 'seed words') is not enough. Please make sure you have backed up both your private key and your descriptor."; pub const BACKUP_DESCRIPTOR_HELP: &str = "In Bitcoin, the coins are locked using a Script (related to the 'address'). In order to recover your funds you need both to know the Scripts you have participated in (your 'addresses'), and be able to sign a transaction that spends from those. For the ability to sign you backup your private key, this is your mnemonics ('seed words'). For finding the coins that belongs to you you backup a template of your Script ( / 'addresses'), this is your descriptor. Note however the descriptor needs not be as securely stored as the private key. A thief that steals your descriptor but not your private key will not be able to steal your funds."; diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index 67d3d10a..96c11170 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -12,7 +12,7 @@ use crate::{ ui::{ color, component::{ - button, card, container, form, + button, card, collapse, container, form, text::{text, Text}, }, icon, @@ -372,7 +372,34 @@ pub fn backup_descriptor<'a>(descriptor: String, done: bool) -> Element<'a, Mess .bold() .size(50), ) - .push(text(super::prompt::BACKUP_DESCRIPTOR_MESSAGE)) + .push( + Column::new() + .push(text(super::prompt::BACKUP_DESCRIPTOR_MESSAGE)) + .push(collapse::Collapse::new( + || { + Button::new( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(text("Learn more").small().bold()) + .push(icon::collapse_icon()), + ) + .style(button::Style::Transparent.into()) + }, + || { + Button::new( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(text("Learn more").small().bold()) + .push(icon::collapsed_icon()), + ) + .style(button::Style::Transparent.into()) + }, + help_backup, + )) + .max_width(1000), + ) .push(card::simple( Column::new() .push(text("The descriptor:").small().bold()) @@ -383,7 +410,8 @@ pub fn backup_descriptor<'a>(descriptor: String, done: bool) -> Element<'a, Mess .on_press(Message::Clibpboard(descriptor)), ), ) - .spacing(10), + .spacing(10) + .max_width(1000), )) .push(Checkbox::new( done, @@ -397,11 +425,6 @@ pub fn backup_descriptor<'a>(descriptor: String, done: bool) -> Element<'a, Mess } else { button::primary(None, "Next").width(Length::Units(200)) }) - .push( - Column::new() - .push(text("Help:").bold()) - .push(text(super::prompt::BACKUP_DESCRIPTOR_HELP).small()), - ) .width(Length::Fill) .height(Length::Fill) .padding(100) @@ -410,6 +433,10 @@ pub fn backup_descriptor<'a>(descriptor: String, done: bool) -> Element<'a, Mess ) } +pub fn help_backup<'a>() -> Element<'a, Message> { + text(super::prompt::BACKUP_DESCRIPTOR_HELP).small().into() +} + pub fn define_bitcoin<'a>( address: &form::Value, cookie_path: &form::Value, diff --git a/gui/src/ui/component/collapse.rs b/gui/src/ui/component/collapse.rs index 480e6c38..839cbd81 100644 --- a/gui/src/ui/component/collapse.rs +++ b/gui/src/ui/component/collapse.rs @@ -5,41 +5,42 @@ use iced::{ use iced_lazy::{self, Component}; use std::marker::PhantomData; -use super::button::Style; +pub struct Collapse<'a, M, H, F, C> { + before: H, + after: F, + content: C, + phantom: PhantomData<&'a M>, +} -pub fn collapse< - 'a, +impl<'a, Message, T, H, F, C> Collapse<'a, Message, H, F, C> +where Message: 'a, T: Into + Clone + 'a, - H: Fn() -> Element<'a, T> + 'a, + H: Fn() -> Button<'a, Event> + 'a, + F: Fn() -> Button<'a, Event> + 'a, C: Fn() -> Element<'a, T> + 'a, ->( - header: H, - content: C, -) -> impl Into> { - Collapse { - header, - content, - phantom: PhantomData, +{ + pub fn new(before: H, after: F, content: C) -> Self { + Collapse { + before, + after, + content, + phantom: PhantomData, + } } } -struct Collapse<'a, H, C> { - header: H, - content: C, - phantom: PhantomData<&'a H>, -} - #[derive(Debug, Clone, Copy)] -enum Event { +pub enum Event { Internal(T), Collapse(bool), } -impl<'a, Message, T, H, C> Component for Collapse<'a, H, C> +impl<'a, Message, T, H, F, C> Component for Collapse<'a, Message, H, F, C> where T: Into + Clone + 'a, - H: Fn() -> Element<'a, T>, + H: Fn() -> Button<'a, Event>, + F: Fn() -> Button<'a, Event>, C: Fn() -> Element<'a, T>, { type State = bool; @@ -58,35 +59,27 @@ where fn view(&self, state: &Self::State) -> Element { if *state { Column::new() - .push( - Button::new((self.header)().map(Event::Internal)) - .style(Style::TransparentBorder.into()) - .padding(10) - .on_press(Event::Collapse(false)), - ) + .push((self.after)().on_press(Event::Collapse(false))) .push((self.content)().map(Event::Internal)) .into() } else { Column::new() - .push( - Button::new((self.header)().map(Event::Internal)) - .style(Style::TransparentBorder.into()) - .padding(10) - .on_press(Event::Collapse(true)), - ) + .push((self.before)().on_press(Event::Collapse(true))) .into() } } } -impl<'a, Message, T, H: 'a, C: 'a> From> for Element<'a, Message> +impl<'a, Message, T, H: 'a, F: 'a, C: 'a> From> + for Element<'a, Message> where Message: 'a, T: Into + Clone + 'a, - H: Fn() -> Element<'a, T, iced::Renderer>, + H: Fn() -> Button<'a, Event, iced::Renderer>, + F: Fn() -> Button<'a, Event, iced::Renderer>, C: Fn() -> Element<'a, T, iced::Renderer>, { - fn from(c: Collapse<'a, H, C>) -> Self { + fn from(c: Collapse<'a, Message, H, F, C>) -> Self { iced_lazy::component(c) } } diff --git a/gui/src/ui/icon.rs b/gui/src/ui/icon.rs index b155a63e..50b7aee6 100644 --- a/gui/src/ui/icon.rs +++ b/gui/src/ui/icon.rs @@ -190,3 +190,11 @@ pub fn done_icon() -> Text<'static> { pub fn todo_icon() -> Text<'static> { icon('\u{F28A}') } + +pub fn collapse_icon() -> Text<'static> { + icon('\u{F284}') +} + +pub fn collapsed_icon() -> Text<'static> { + icon('\u{F282}') +}