diff --git a/gui/src/app/state/receive.rs b/gui/src/app/state/receive.rs index e5dac8ce..cc0c9cf3 100644 --- a/gui/src/app/state/receive.rs +++ b/gui/src/app/state/receive.rs @@ -27,6 +27,12 @@ use crate::daemon::{ Daemon, }; +pub enum Modal { + VerifyAddress(VerifyAddressModal), + ShowQrCode(ShowQrCodeModal), + None, +} + #[derive(Debug, Default)] pub struct Addresses { list: Vec
, @@ -57,8 +63,7 @@ pub struct ReceivePanel { wallet: Arc, addresses: Addresses, labels_edited: LabelsEdited, - qr_code: Option, - modal: Option, + modal: Modal, warning: Option, } @@ -69,8 +74,7 @@ impl ReceivePanel { wallet, addresses: Addresses::default(), labels_edited: LabelsEdited::default(), - qr_code: None, - modal: None, + modal: Modal::None, warning: None, } } @@ -84,22 +88,24 @@ impl State for ReceivePanel { self.warning.as_ref(), view::receive::receive( &self.addresses.list, - self.qr_code.as_ref(), &self.addresses.labels, self.labels_edited.cache(), ), ); - if let Some(m) = &self.modal { - modal::Modal::new(content, m.view()) + + match &self.modal { + Modal::VerifyAddress(m) => modal::Modal::new(content, m.view()) .on_blur(Some(view::Message::Close)) - .into() - } else { - content + .into(), + Modal::ShowQrCode(m) => modal::Modal::new(content, m.view()) + .on_blur(Some(view::Message::Close)) + .into(), + Modal::None => content, } } fn subscription(&self) -> Subscription { - if let Some(modal) = &self.modal { + if let Modal::VerifyAddress(modal) = &self.modal { modal.subscription() } else { Subscription::none() @@ -130,11 +136,6 @@ impl State for ReceivePanel { match res { Ok((address, derivation_index)) => { self.warning = None; - self.qr_code = qr_code::State::new(format!( - "bitcoin:{}?index={}", - address, derivation_index - )) - .ok(); self.addresses.list.push(address); self.addresses.derivation_indexes.push(derivation_index); } @@ -143,11 +144,11 @@ impl State for ReceivePanel { Command::none() } Message::View(view::Message::Close) => { - self.modal = None; + self.modal = Modal::None; Command::none() } Message::View(view::Message::Select(i)) => { - self.modal = Some(VerifyAddressModal::new( + self.modal = Modal::VerifyAddress(VerifyAddressModal::new( self.data_dir.clone(), self.wallet.clone(), cache.network, @@ -172,11 +173,21 @@ impl State for ReceivePanel { Message::ReceiveAddress, ) } - _ => self - .modal - .as_mut() - .map(|m| m.update(daemon, cache, message)) - .unwrap_or_else(Command::none), + Message::View(view::Message::ShowQrCode(i)) => { + if let Some(address) = self.addresses.list.get(i) { + if let Some(modal) = ShowQrCodeModal::new(address, i) { + self.modal = Modal::ShowQrCode(modal); + } + } + Command::none() + } + _ => { + if let Modal::VerifyAddress(ref mut m) = self.modal { + m.update(daemon, cache, message) + } else { + Command::none() + } + } } } @@ -290,6 +301,26 @@ impl VerifyAddressModal { } } +pub struct ShowQrCodeModal { + qr_code: qr_code::State, + address: String, +} + +impl ShowQrCodeModal { + pub fn new(address: &Address, i: usize) -> Option { + qr_code::State::new(format!("bitcoin:{}?index={}", address, i)) + .ok() + .map(|qr_code| Self { + qr_code, + address: address.to_string(), + }) + } + + fn view(&self) -> Element { + view::receive::qr_modal(&self.qr_code, &self.address) + } +} + async fn verify_address( hw: std::sync::Arc, index: ChildNumber, diff --git a/gui/src/app/view/message.rs b/gui/src/app/view/message.rs index 36d9511a..2b7b0e87 100644 --- a/gui/src/app/view/message.rs +++ b/gui/src/app/view/message.rs @@ -18,6 +18,7 @@ pub enum Message { Previous, SelectHardwareWallet(usize), CreateRbf(CreateRbfMessage), + ShowQrCode(usize), } #[derive(Debug, Clone)] diff --git a/gui/src/app/view/receive.rs b/gui/src/app/view/receive.rs index 508b145c..03a8e3c2 100644 --- a/gui/src/app/view/receive.rs +++ b/gui/src/app/view/receive.rs @@ -3,10 +3,11 @@ use std::collections::{HashMap, HashSet}; use iced::{ widget::{ qr_code::{self, QRCode}, - scrollable, Space, + scrollable, }, Alignment, Length, }; +use iced_native::widget::Space; use liana::miniscript::bitcoin::{ self, @@ -37,7 +38,6 @@ use super::message::Message; pub fn receive<'a>( addresses: &'a [bitcoin::Address], - qr: Option<&'a qr_code::State>, labels: &'a HashMap, labels_editing: &'a HashMap>, ) -> Element<'a, Message> { @@ -111,22 +111,23 @@ pub fn receive<'a>( .align_items(Alignment::Center), ) .push( - button::primary(None, "Verify on hardware device") - .on_press(Message::Select(i)), + Row::new() + .push( + button::primary(None, "Verify on hardware device") + .on_press(Message::Select(i)), + ) + .push(Space::with_width(Length::Fill)) + .push( + button::primary(None, "Show QR Code") + .on_press(Message::ShowQrCode(i)), + ), ) .spacing(10), ) .padding(20), ) }, - )) - .push(if let Some(qr) = qr { - Container::new(QRCode::new(qr).cell_size(5)) - .padding(10) - .style(theme::Container::QrCode) - } else { - Container::new(Space::with_width(Length::Fill)).width(Length::Fixed(200.0)) - }), + )), ) .spacing(20) .into() @@ -214,3 +215,26 @@ pub fn verify_address_modal<'a>( .max_width(750) .into() } + +pub fn qr_modal<'a>(qr: &'a qr_code::State, address: &'a String) -> Element<'a, Message> { + Column::new() + .push( + Row::new() + .push(Space::with_width(Length::Fill)) + .push( + Container::new(QRCode::new(qr).cell_size(8)) + .padding(10) + .style(theme::Container::QrCode), + ) + .push(Space::with_width(Length::Fill)), + ) + .push(Space::with_height(Length::Fixed(15.0))) + .push( + Container::new(text(address).size(15)) + .width(Length::Fill) + .center_x(), + ) + .width(Length::Fill) + .max_width(400) + .into() +}