From 1a48097d10a9945532e679f809ccdc6e5d15eb49 Mon Sep 17 00:00:00 2001 From: edouardparis Date: Fri, 12 Jan 2024 15:56:27 +0100 Subject: [PATCH] ui: add processing hw notification to components --- gui/src/app/state/psbt.rs | 2 +- gui/src/app/view/psbt.rs | 24 ++++++-- gui/ui/src/component/notification.rs | 92 +++++++++++++++++++++++++++- gui/ui/src/component/toast.rs | 8 +-- gui/ui/src/theme.rs | 51 ++++++++++++++- 5 files changed, 163 insertions(+), 14 deletions(-) diff --git a/gui/src/app/state/psbt.rs b/gui/src/app/state/psbt.rs index 0f5b2b410..623a3a728 100644 --- a/gui/src/app/state/psbt.rs +++ b/gui/src/app/state/psbt.rs @@ -504,7 +504,7 @@ impl Action for SignAction { fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message> { let content = toast::Manager::new( content, - view::psbt::sign_action_toasts(&self.hws.list, &self.signing), + view::psbt::sign_action_toasts(self.error.as_ref(), &self.hws.list, &self.signing), ) .into(); if self.display_modal { diff --git a/gui/src/app/view/psbt.rs b/gui/src/app/view/psbt.rs index 0ec555b04..4033181c1 100644 --- a/gui/src/app/view/psbt.rs +++ b/gui/src/app/view/psbt.rs @@ -993,10 +993,12 @@ pub fn sign_action<'a>( } pub fn sign_action_toasts<'a>( + error: Option<&Error>, hws: &'a [HardwareWallet], signing: &HashSet, ) -> Vec> { - hws.iter() + let mut vec: Vec> = hws + .iter() .filter_map(|hw| { if let HardwareWallet::Supported { kind, @@ -1008,13 +1010,13 @@ pub fn sign_action_toasts<'a>( { if signing.contains(fingerprint) { Some( - card::simple(liana_ui::component::hw::processing_hardware_wallet( + liana_ui::component::notification::processing_hardware_wallet( kind, version.as_ref(), fingerprint, alias.as_ref(), - )) - .width(Length::Fixed(500.0)) + ) + .max_width(400.0) .into(), ) } else { @@ -1024,7 +1026,19 @@ pub fn sign_action_toasts<'a>( None } }) - .collect() + .collect(); + if let Some(e) = error { + vec.push( + liana_ui::component::notification::processing_hardware_wallet_error( + "Device failed to sign".to_string(), + e.to_string(), + ) + .max_width(400.0) + .into(), + ) + } + + vec } pub fn update_spend_view<'a>( diff --git a/gui/ui/src/component/notification.rs b/gui/ui/src/component/notification.rs index 9a2cef653..f70045e91 100644 --- a/gui/ui/src/component/notification.rs +++ b/gui/ui/src/component/notification.rs @@ -1,10 +1,17 @@ +use std::borrow::Cow; +use std::fmt::Display; + use crate::{ color, component::{collapse, text}, icon, theme, + util::*, widget::*, }; -use iced::{Alignment, Length}; +use iced::{ + widget::{column, container, row}, + Alignment, Length, +}; pub fn warning<'a, T: 'a + Clone>(message: String, error: String) -> Container<'a, T> { let message_clone = message.clone(); @@ -51,3 +58,86 @@ pub fn warning<'a, T: 'a + Clone>(message: String, error: String) -> Container<' .style(theme::Container::Card(theme::Card::Warning)) .width(Length::Fill) } + +pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>( + kind: K, + version: Option, + fingerprint: F, + alias: Option>>, +) -> Container<'a, T> { + container( + row(vec![ + column(vec![ + Row::new() + .spacing(5) + .push_maybe(alias.map(|a| text::p1_bold(a))) + .push(text::p1_regular(format!("#{}", fingerprint))) + .into(), + Row::new() + .spacing(5) + .push(text::caption(kind.to_string())) + .push_maybe(version.map(|v| text::caption(v.to_string()))) + .into(), + ]) + .width(Length::Fill) + .into(), + column(vec![ + text::p2_regular("Processing...").into(), + text::p2_regular("Please check your device").into(), + ]) + .into(), + ]) + .align_items(Alignment::Center), + ) + .style(theme::Container::Notification(theme::Notification::Pending)) + .padding(10) +} + +pub fn processing_hardware_wallet_error<'a, T: 'a + Clone>( + message: String, + error: String, +) -> Container<'a, T> { + let message_clone = message.clone(); + Container::new(Container::new(collapse::Collapse::new( + move || { + Button::new( + Row::new() + .push( + Container::new( + text::p1_bold(message_clone.to_string()).style(color::LIGHT_BLACK), + ) + .width(Length::Fill), + ) + .push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(text::p1_bold("Learn more").style(color::LIGHT_BLACK)) + .push(icon::collapse_icon().style(color::LIGHT_BLACK)), + ), + ) + .style(theme::Button::Transparent) + }, + move || { + Button::new( + Row::new() + .push( + Container::new(text::p1_bold(message.to_owned()).style(color::LIGHT_BLACK)) + .width(Length::Fill), + ) + .push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(text::p1_bold("Learn more").style(color::LIGHT_BLACK)) + .push(icon::collapsed_icon().style(color::LIGHT_BLACK)), + ), + ) + .style(theme::Button::Transparent) + }, + move || Element::<'a, T>::from(text::p2_regular(error.to_owned())), + ))) + .padding(10) + .style(theme::Container::Notification(theme::Notification::Error)) + .width(Length::Fill) +} diff --git a/gui/ui/src/component/toast.rs b/gui/ui/src/component/toast.rs index 94df4f24b..7a3e3fdd8 100644 --- a/gui/ui/src/component/toast.rs +++ b/gui/ui/src/component/toast.rs @@ -1,14 +1,10 @@ -use std::fmt; -use std::time::{Duration, Instant}; +use std::time::Instant; -use super::card; -use super::text::h1; use super::theme::Theme; -use crate::widget::*; use iced::{Alignment, Element, Length, Point, Rectangle, Size, Vector}; use iced_native::widget::{Operation, Tree}; -use iced_native::{event, layout, mouse, overlay, renderer, window}; +use iced_native::{event, layout, mouse, overlay, renderer}; use iced_native::{Clipboard, Event, Layout, Shell, Widget}; pub trait Toast { diff --git a/gui/ui/src/theme.rs b/gui/ui/src/theme.rs index 777ba1a07..e1a37aefd 100644 --- a/gui/ui/src/theme.rs +++ b/gui/ui/src/theme.rs @@ -93,6 +93,7 @@ pub enum Container { Badge(Badge), Pill(Pill), Custom(iced::Color), + Notification(Notification), QrCode, } @@ -122,6 +123,7 @@ impl container::StyleSheet for Theme { Container::Card(c) => c.appearance(self), Container::Badge(c) => c.appearance(self), Container::Pill(c) => c.appearance(self), + Container::Notification(c) => c.appearance(self), Container::Custom(c) => container::Appearance { background: (*c).into(), ..container::Appearance::default() @@ -154,6 +156,7 @@ impl container::StyleSheet for Theme { Container::Card(c) => c.appearance(self), Container::Badge(c) => c.appearance(self), Container::Pill(c) => c.appearance(self), + Container::Notification(c) => c.appearance(self), Container::Custom(c) => container::Appearance { background: (*c).into(), ..container::Appearance::default() @@ -186,6 +189,52 @@ impl From for Container { } } +#[derive(Debug, Copy, Clone, Default)] +pub enum Notification { + #[default] + Pending, + Error, +} + +impl Notification { + fn appearance(&self, theme: &Theme) -> iced::widget::container::Appearance { + match theme { + Theme::Light => match self { + Self::Pending => container::Appearance { + background: color::GREEN.into(), + text_color: color::LIGHT_BLACK.into(), + border_width: 1.0, + border_color: color::GREEN, + border_radius: 25.0, + }, + Self::Error => container::Appearance { + background: color::ORANGE.into(), + text_color: color::LIGHT_BLACK.into(), + border_width: 1.0, + border_color: color::ORANGE.into(), + border_radius: 25.0, + }, + }, + Theme::Dark => match self { + Self::Pending => container::Appearance { + background: color::GREEN.into(), + text_color: color::LIGHT_BLACK.into(), + border_width: 1.0, + border_color: color::GREEN, + border_radius: 25.0, + }, + Self::Error => container::Appearance { + background: color::ORANGE.into(), + text_color: color::LIGHT_BLACK.into(), + border_width: 1.0, + border_color: color::ORANGE.into(), + border_radius: 25.0, + }, + }, + } + } +} + #[derive(Debug, Copy, Clone, Default)] pub enum Card { #[default] @@ -574,7 +623,7 @@ impl button::StyleSheet for Theme { }, Button::Transparent => button::Appearance { shadow_offset: iced::Vector::default(), - background: color::GREY_7.into(), + background: iced::Color::TRANSPARENT.into(), border_radius: 25.0, border_width: 0.0, border_color: iced::Color::TRANSPARENT,