diff --git a/gui/src/app/menu.rs b/gui/src/app/menu.rs index cca33768..ddeb4b09 100644 --- a/gui/src/app/menu.rs +++ b/gui/src/app/menu.rs @@ -1,5 +1,6 @@ #[derive(Debug, Clone, PartialEq, Eq)] pub enum Menu { Home, + Receive, Settings, } diff --git a/gui/src/app/message.rs b/gui/src/app/message.rs index 6183977f..c4e2cabc 100644 --- a/gui/src/app/message.rs +++ b/gui/src/app/message.rs @@ -10,4 +10,5 @@ pub enum Message { LoadDaemonConfig(Box), DaemonConfigLoaded(Result<(), Error>), BlockHeight(Result), + ReceiveAddress(Result), } diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index f6dfcccf..c55a87f2 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -21,7 +21,7 @@ pub use minisafe::config::Config as DaemonConfig; pub use config::Config; pub use message::Message; -use state::{Home, State}; +use state::{Home, ReceivePanel, State}; use crate::{ app::{cache::Cache, error::Error, menu::Menu}, @@ -63,6 +63,7 @@ impl App { .into() } menu::Menu::Home => Home {}.into(), + menu::Menu::Receive => ReceivePanel::default().into(), }; self.state.load(self.daemon.clone()) } diff --git a/gui/src/app/state/mod.rs b/gui/src/app/state/mod.rs index aa87e7b2..18dd4242 100644 --- a/gui/src/app/state/mod.rs +++ b/gui/src/app/state/mod.rs @@ -3,9 +3,9 @@ mod settings; use std::sync::Arc; use iced::pure::{column, Element}; -use iced::{Command, Subscription}; +use iced::{widget::qr_code, Command, Subscription}; -use super::{cache::Cache, menu::Menu, message::Message, view}; +use super::{cache::Cache, error::Error, menu::Menu, message::Message, view}; pub use settings::SettingsState; @@ -15,7 +15,7 @@ pub trait State { fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message>; fn update( &mut self, - daemon: Arc, + daemon: Arc, cache: &Cache, message: Message, ) -> Command; @@ -35,7 +35,7 @@ impl State for Home { } fn update( &mut self, - _daemon: Arc, + _daemon: Arc, _cache: &Cache, _message: Message, ) -> Command { @@ -48,3 +48,61 @@ impl From for Box { Box::new(s) } } + +#[derive(Default)] +pub struct ReceivePanel { + address: Option, + qr_code: Option, + warning: Option, +} + +impl State for ReceivePanel { + fn view<'a>(&'a self, _cache: &'a Cache) -> Element<'a, view::Message> { + if let Some(address) = &self.address { + view::dashboard( + &Menu::Receive, + self.warning.as_ref(), + view::receive::receive(address, self.qr_code.as_ref().unwrap()), + ) + } else { + view::dashboard(&Menu::Receive, self.warning.as_ref(), column()) + } + } + fn update( + &mut self, + _daemon: Arc, + _cache: &Cache, + message: Message, + ) -> Command { + if let Message::ReceiveAddress(res) = message { + match res { + Ok(address) => { + self.warning = None; + self.qr_code = Some(qr_code::State::new(&address.to_qr_uri()).unwrap()); + self.address = Some(address); + } + Err(e) => self.warning = Some(e), + } + }; + Command::none() + } + + fn load(&self, daemon: Arc) -> Command { + let daemon = daemon.clone(); + Command::perform( + async move { + daemon + .get_new_address() + .map(|res| res.address) + .map_err(|e| e.into()) + }, + Message::ReceiveAddress, + ) + } +} + +impl From for Box { + fn from(s: ReceivePanel) -> Box { + Box::new(s) + } +} diff --git a/gui/src/app/view/mod.rs b/gui/src/app/view/mod.rs index d2b66791..d5d05d5d 100644 --- a/gui/src/app/view/mod.rs +++ b/gui/src/app/view/mod.rs @@ -1,6 +1,7 @@ mod message; mod warning; +pub mod receive; pub mod settings; pub use message::*; @@ -14,7 +15,7 @@ use iced::{ use crate::ui::{ color, component::{button, separation, text::*}, - icon::{home_icon, settings_icon}, + icon::{home_icon, receive_icon, settings_icon}, }; use crate::app::{error::Error, menu::Menu}; @@ -29,6 +30,17 @@ pub fn sidebar(menu: &Menu) -> widget::Container { .on_press(Message::Menu(Menu::Home)) .width(iced::Length::Units(200)) }; + + let receive_button = if *menu == Menu::Receive { + button::primary(Some(receive_icon()), "Receive") + .on_press(Message::Reload) + .width(iced::Length::Units(200)) + } else { + button::transparent(Some(receive_icon()), "Receive") + .on_press(Message::Menu(Menu::Receive)) + .width(iced::Length::Units(200)) + }; + let settings_button = if *menu == Menu::Settings { button::primary(Some(settings_icon()), "Settings") .on_press(Message::Menu(Menu::Settings)) @@ -51,6 +63,7 @@ pub fn sidebar(menu: &Menu) -> widget::Container { .spacing(10), ) .push(home_button) + .push(receive_button) .spacing(20) .height(Length::Fill), ) diff --git a/gui/src/app/view/receive.rs b/gui/src/app/view/receive.rs new file mode 100644 index 00000000..0d931d78 --- /dev/null +++ b/gui/src/app/view/receive.rs @@ -0,0 +1,32 @@ +use iced::{ + pure::{column, row, widget::Button, Element}, + widget::qr_code::{self, QRCode}, + Alignment, +}; + +use crate::ui::{ + component::{button, card, text::*}, + icon, +}; + +use super::message::Message; + +pub fn receive<'a>(address: &'a bitcoin::Address, qr: &'a qr_code::State) -> Element<'a, Message> { + card::simple( + column() + .push(QRCode::new(qr).cell_size(10)) + .push( + row() + .push(text(&address.to_string()).small()) + .push( + Button::new(icon::clipboard_icon()) + .on_press(Message::Clipboard(address.to_string())) + .style(button::Style::TransparentBorder), + ) + .align_items(Alignment::Center), + ) + .align_items(Alignment::Center) + .spacing(20), + ) + .into() +} diff --git a/gui/src/ui/icon.rs b/gui/src/ui/icon.rs index 497bd5af..a769cb00 100644 --- a/gui/src/ui/icon.rs +++ b/gui/src/ui/icon.rs @@ -50,7 +50,7 @@ pub fn connected_device_icon() -> Text { icon('\u{F350}') } -pub fn deposit_icon() -> Text { +pub fn receive_icon() -> Text { icon('\u{F123}') }