diff --git a/gui/src/app/state/spend/step.rs b/gui/src/app/state/spend/step.rs index 56fe9861..3e77f10d 100644 --- a/gui/src/app/state/spend/step.rs +++ b/gui/src/app/state/spend/step.rs @@ -43,12 +43,33 @@ pub trait Step { pub struct ChooseRecipients { recipients: Vec, + is_valid: bool, + is_duplicate: bool, } impl std::default::Default for ChooseRecipients { fn default() -> Self { Self { recipients: vec![Recipient::default()], + is_valid: false, + is_duplicate: false, + } + } +} + +impl ChooseRecipients { + fn check_valid(&mut self) { + self.is_valid = !self.recipients.is_empty(); + self.is_duplicate = false; + for (i, recipient) in self.recipients.iter().enumerate() { + if !recipient.valid() { + self.is_valid = false; + } + if !self.is_duplicate { + self.is_duplicate = self.recipients[..i] + .iter() + .any(|r| r.address.value == recipient.address.value); + } } } } @@ -74,6 +95,8 @@ impl Step for ChooseRecipients { } _ => {} } + + self.check_valid(); } Command::none() } @@ -102,7 +125,8 @@ impl Step for ChooseRecipients { .map(|r| r.amount().unwrap_or(0_u64)) .sum(), ), - !self.recipients.iter().any(|recipient| !recipient.valid()), + self.is_valid, + self.is_duplicate, ) } } @@ -282,6 +306,7 @@ impl ChooseCoins { impl Step for ChooseCoins { fn load(&mut self, draft: &TransactionDraft) { + self.warning = None; self.recipients = draft .outputs .iter() diff --git a/gui/src/app/view/spend/detail.rs b/gui/src/app/view/spend/detail.rs index 5e844bce..a5417d8e 100644 --- a/gui/src/app/view/spend/detail.rs +++ b/gui/src/app/view/spend/detail.rs @@ -8,7 +8,7 @@ use liana::miniscript::bitcoin::{util::bip32::Fingerprint, Address, Amount, Netw use crate::{ app::{ error::Error, - view::{message::*, modal_section, warning::warn}, + view::{message::*, warning::warn}, }, daemon::model::{Coin, SpendStatus, SpendTx}, hw::HardwareWallet, @@ -155,9 +155,15 @@ pub fn spend_modal<'a, T: Into>>( .padding(10) .style(container::Style::Background), ) - .push(modal_section(Container::new( - Container::new(Scrollable::new(content)).max_width(750), - ))) + .push( + Container::new(Scrollable::new( + Container::new(Container::new(content).max_width(750)) + .width(Length::Fill) + .center_x(), + )) + .height(Length::Fill) + .style(container::Style::Background), + ) .width(Length::Fill) .height(Length::Fill) .into() diff --git a/gui/src/app/view/spend/step.rs b/gui/src/app/view/spend/step.rs index 23f7e758..50959694 100644 --- a/gui/src/app/view/spend/step.rs +++ b/gui/src/app/view/spend/step.rs @@ -27,6 +27,7 @@ pub fn choose_recipients_view( recipients: Vec>, total_amount: Amount, is_valid: bool, + duplicate: bool, ) -> Element { modal( false, @@ -49,11 +50,17 @@ pub fn choose_recipients_view( Some( Container::new( Row::new() + .spacing(20) .align_items(Alignment::Center) .push( Container::new(text(format!("{}", total_amount)).bold()) .width(Length::Fill), ) + .push_maybe(if duplicate { + Some(text("Two recipient addresses are the same").style(color::WARNING)) + } else { + None + }) .push(if is_valid { button::primary(None, "Next") .on_press(Message::Next)