From 1fd53c0ff41579196de0592d250ffd224a1bd8e7 Mon Sep 17 00:00:00 2001 From: edouard Date: Tue, 9 May 2023 16:24:30 +0200 Subject: [PATCH 1/7] gui: Add iconex icons --- gui/src/app/view/coins.rs | 10 +- gui/src/app/view/mod.rs | 149 ++-------- gui/src/app/view/recovery.rs | 116 ++++---- gui/src/app/view/transactions.rs | 2 + gui/ui/src/component/badge.rs | 9 + gui/ui/src/component/button.rs | 8 +- gui/ui/src/component/card.rs | 2 +- gui/ui/src/icon.rs | 259 +++++++----------- gui/ui/src/image.rs | 24 -- gui/ui/static/icons/clock-icon.svg | 6 - gui/ui/static/icons/clock-red-icon.svg | 6 - gui/ui/static/icons/coins-icon.svg | 3 - gui/ui/static/icons/iconex/iconex-icons.ttf | Bin 0 -> 7608 bytes gui/ui/static/icons/iconex/svg/IconBack.svg | 4 + .../static/icons/iconex/svg/IconBroadcast.svg | 4 + gui/ui/static/icons/iconex/svg/IconCheck.svg | 4 + gui/ui/static/icons/iconex/svg/IconClear.svg | 5 + gui/ui/static/icons/iconex/svg/IconCoins.svg | 3 + gui/ui/static/icons/iconex/svg/IconCopy.svg | 4 + gui/ui/static/icons/iconex/svg/IconDown.svg | 3 + .../svg/IconHistory.svg} | 0 gui/ui/static/icons/iconex/svg/IconHome.svg | 6 + gui/ui/static/icons/iconex/svg/IconImport.svg | 5 + gui/ui/static/icons/iconex/svg/IconKey.svg | 7 + gui/ui/static/icons/iconex/svg/IconPlus.svg | 5 + .../static/icons/iconex/svg/IconReceive.svg | 5 + .../static/icons/iconex/svg/IconRefresh.svg | 3 + .../static/icons/iconex/svg/IconSablier.svg | 6 + gui/ui/static/icons/iconex/svg/IconSave.svg | 5 + gui/ui/static/icons/iconex/svg/IconSend.svg | 5 + gui/ui/static/icons/iconex/svg/IconTime.svg | 4 + .../static/icons/iconex/svg/IconeSettings.svg | 4 + gui/ui/static/icons/iconex/svg_to_ttf.py | 33 +++ 33 files changed, 315 insertions(+), 394 deletions(-) delete mode 100644 gui/ui/static/icons/clock-icon.svg delete mode 100644 gui/ui/static/icons/clock-red-icon.svg delete mode 100644 gui/ui/static/icons/coins-icon.svg create mode 100644 gui/ui/static/icons/iconex/iconex-icons.ttf create mode 100644 gui/ui/static/icons/iconex/svg/IconBack.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconBroadcast.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconCheck.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconClear.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconCoins.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconCopy.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconDown.svg rename gui/ui/static/icons/{history-icon.svg => iconex/svg/IconHistory.svg} (100%) create mode 100644 gui/ui/static/icons/iconex/svg/IconHome.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconImport.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconKey.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconPlus.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconReceive.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconRefresh.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconSablier.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconSave.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconSend.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconTime.svg create mode 100644 gui/ui/static/icons/iconex/svg/IconeSettings.svg create mode 100644 gui/ui/static/icons/iconex/svg_to_ttf.py diff --git a/gui/src/app/view/coins.rs b/gui/src/app/view/coins.rs index 29f8b002..7a9e219d 100644 --- a/gui/src/app/view/coins.rs +++ b/gui/src/app/view/coins.rs @@ -3,9 +3,7 @@ use iced::{widget::Space, Alignment, Length}; use liana_ui::{ color, component::{amount::*, badge, button, text::*}, - icon, - image::*, - theme, + icon, theme, util::Collection, widget::*, }; @@ -182,7 +180,7 @@ pub fn coin_sequence_label<'a, T: 'a>(seq: u32, timelock: u32) -> Container<'a, Container::new( Row::new() .spacing(5) - .push(clock_red_icon().width(Length::Units(20))) + .push(icon::clock_icon().width(Length::Units(20))) .push(p2_regular("Expired")) .align_items(Alignment::Center), ) @@ -192,7 +190,7 @@ pub fn coin_sequence_label<'a, T: 'a>(seq: u32, timelock: u32) -> Container<'a, Container::new( Row::new() .spacing(5) - .push(clock_red_icon().width(Length::Units(20))) + .push(icon::clock_icon().width(Length::Units(20))) .push(p2_regular(expire_message(seq))) .align_items(Alignment::Center), ) @@ -202,7 +200,7 @@ pub fn coin_sequence_label<'a, T: 'a>(seq: u32, timelock: u32) -> Container<'a, Container::new( Row::new() .spacing(5) - .push(clock_icon().width(Length::Units(20))) + .push(icon::clock_icon().width(Length::Units(20))) .push(p2_regular(expire_message(seq)).style(color::GREY_3)) .align_items(Alignment::Center), ) diff --git a/gui/src/app/view/mod.rs b/gui/src/app/view/mod.rs index 699e0cb3..6844e035 100644 --- a/gui/src/app/view/mod.rs +++ b/gui/src/app/view/mod.rs @@ -23,7 +23,9 @@ use iced::{ use liana_ui::{ color, component::{button, text::*}, - icon::{cross_icon, home_icon, receive_icon, send_icon, settings_icon}, + icon::{ + coins_icon, cross_icon, history_icon, home_icon, receive_icon, send_icon, settings_icon, + }, image::*, theme, util::Collection, @@ -54,150 +56,55 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> { let transactions_button = if *menu == Menu::Transactions { row!( - Button::new( - row!( - history_icon().width(Length::Units(20)), - text("Transactions") - ) - .spacing(10) - .padding(10) - .align_items(iced::Alignment::Center), - ) - .style(theme::Button::Menu(true)) - .on_press(Message::Menu(Menu::Transactions)) - .width(iced::Length::Fill), + button::menu_active(Some(history_icon()), "Transactions") + .on_press(Message::Menu(Menu::Transactions)) + .width(iced::Length::Fill), menu_green_bar() ) } else { - row!(Button::new( - row!( - history_icon().width(Length::Units(20)), - text("Transactions") - ) - .spacing(10) - .padding(10) - .align_items(iced::Alignment::Center), - ) - .style(theme::Button::Menu(false)) - .on_press(Message::Menu(Menu::Transactions)) - .width(iced::Length::Fill)) + row!(button::menu(Some(history_icon()), "Transactions") + .on_press(Message::Menu(Menu::Transactions)) + .width(iced::Length::Fill)) }; let coins_button = if *menu == Menu::Coins { row!( - Button::new( - Container::new( - Row::new() - .push(coins_icon().width(Length::Units(20))) - .push(text("Coins")) - .spacing(10) - .width(iced::Length::Fill) - .align_items(iced::Alignment::Center), - ) - .width(iced::Length::Fill) - .padding(10) - .center_x(), - ) - .style(theme::Button::Menu(true)) - .on_press(Message::Reload) - .width(iced::Length::Fill), + button::menu_active(Some(coins_icon()), "Coins") + .on_press(Message::Reload) + .width(iced::Length::Fill), menu_green_bar() ) } else { - row!(Button::new( - Container::new( - Row::new() - .push(coins_icon().width(Length::Units(20))) - .push(text("Coins")) - .spacing(10) - .width(iced::Length::Fill) - .align_items(iced::Alignment::Center), - ) - .width(iced::Length::Fill) - .padding(10) - .center_x(), - ) - .style(theme::Button::Menu(false)) - .on_press(Message::Menu(Menu::Coins)) - .width(iced::Length::Fill)) + row!(button::menu(Some(coins_icon()), "Coins") + .style(theme::Button::Menu(false)) + .on_press(Message::Menu(Menu::Coins)) + .width(iced::Length::Fill)) }; let psbt_button = if *menu == Menu::PSBTs { row!( - Button::new( - Container::new( - Row::new() - .push(history_icon().width(Length::Units(20))) - .push(text("PSBTs")) - .spacing(10) - .width(iced::Length::Fill) - .align_items(iced::Alignment::Center), - ) - .width(iced::Length::Fill) - .padding(10) - .center_x(), - ) - .style(theme::Button::Menu(true)) - .on_press(Message::Menu(Menu::PSBTs)) - .width(iced::Length::Fill), + button::menu_active(Some(history_icon()), "PSBTs") + .on_press(Message::Menu(Menu::PSBTs)) + .width(iced::Length::Fill), menu_green_bar() ) } else { - row!(Button::new( - Container::new( - Row::new() - .push(history_icon().width(Length::Units(20))) - .push(text("PSBTs")) - .spacing(10) - .width(iced::Length::Fill) - .align_items(iced::Alignment::Center), - ) - .width(iced::Length::Fill) - .padding(10) - .center_x(), - ) - .style(theme::Button::Menu(false)) - .on_press(Message::Menu(Menu::PSBTs)) - .width(iced::Length::Fill)) + row!(button::menu(Some(history_icon()), "PSBTs") + .on_press(Message::Menu(Menu::PSBTs)) + .width(iced::Length::Fill)) }; let spend_button = if *menu == Menu::CreateSpendTx { row!( - Button::new( - Container::new( - Row::new() - .push(send_icon()) - .push(text("Send")) - .spacing(10) - .width(iced::Length::Fill) - .align_items(iced::Alignment::Center), - ) - .width(iced::Length::Fill) - .padding(10) - .center_x(), - ) - .style(theme::Button::Menu(true)) - .on_press(Message::Menu(Menu::CreateSpendTx)) - .width(iced::Length::Fill), + button::menu_active(Some(send_icon()), "Send") + .on_press(Message::Menu(Menu::CreateSpendTx)) + .width(iced::Length::Fill), menu_green_bar() ) } else { - row!(Button::new( - Container::new( - Row::new() - .push(send_icon()) - .push(text("Send")) - .spacing(10) - .width(iced::Length::Fill) - .align_items(iced::Alignment::Center), - ) - .width(iced::Length::Fill) - .padding(10) - .center_x(), - ) - .style(theme::Button::Menu(false)) - .on_press(Message::Menu(Menu::CreateSpendTx)) - .width(iced::Length::Fill)) + row!(button::menu(Some(send_icon()), "Send") + .on_press(Message::Menu(Menu::CreateSpendTx)) + .width(iced::Length::Fill)) }; let receive_button = if *menu == Menu::Receive { diff --git a/gui/src/app/view/recovery.rs b/gui/src/app/view/recovery.rs index 1e197830..fe7ce4d0 100644 --- a/gui/src/app/view/recovery.rs +++ b/gui/src/app/view/recovery.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use iced::{ - widget::{tooltip, Space}, + widget::{checkbox, tooltip, Space}, Alignment, Length, }; @@ -116,68 +116,60 @@ pub fn recovery_path_view<'a>( selected: bool, ) -> Element<'a, Message> { Container::new( - Button::new( - Row::new() - .push(if selected { - icon::square_check_icon() - } else { - icon::square_icon() - }) - .push( - Column::new() - .push( - Row::new() - .align_items(Alignment::Center) - .spacing(10) - .push( - text(format!( - "{} signature{} from", - threshold, - if threshold > 1 { "s" } else { "" } - )) - .bold(), - ) - .push(origins.iter().fold( - Row::new().align_items(Alignment::Center).spacing(5), - |row, (fg, _)| { - row.push(if let Some(alias) = key_aliases.get(fg) { - Container::new( - tooltip::Tooltip::new( - Container::new(text(alias)).padding(3).style( - theme::Container::Pill(theme::Pill::Simple), - ), - fg.to_string(), - tooltip::Position::Bottom, - ) - .style(theme::Container::Card(theme::Card::Simple)), + Row::new() + .push(checkbox("", selected, move |_| { + Message::CreateSpend(CreateSpendMessage::SelectPath(index)) + })) + .push( + Column::new() + .push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push( + text(format!( + "{} signature{} from", + threshold, + if threshold > 1 { "s" } else { "" } + )) + .bold(), + ) + .push(origins.iter().fold( + Row::new().align_items(Alignment::Center).spacing(5), + |row, (fg, _)| { + row.push(if let Some(alias) = key_aliases.get(fg) { + Container::new( + tooltip::Tooltip::new( + Container::new(text(alias)).padding(3).style( + theme::Container::Pill(theme::Pill::Simple), + ), + fg.to_string(), + tooltip::Position::Bottom, ) - } else { - Container::new(text(fg.to_string())) - .padding(3) - .style(theme::Container::Pill(theme::Pill::Simple)) - }) - }, - )), - ) - .push( - Row::new() - .spacing(5) - .push(text("can recover")) - .push(text(format!( - "{} coin{} totalling", - number_of_coins, - if number_of_coins > 0 { "s" } else { "" } - ))) - .push(amount(&total_amount)), - ), - ) - .align_items(Alignment::Center) - .spacing(20), - ) - .padding(10) - .width(Length::Fill) - .on_press(Message::CreateSpend(CreateSpendMessage::SelectPath(index))) - .style(theme::Button::TransparentBorder), + .style(theme::Container::Card(theme::Card::Simple)), + ) + } else { + Container::new(text(fg.to_string())) + .padding(3) + .style(theme::Container::Pill(theme::Pill::Simple)) + }) + }, + )), + ) + .push( + Row::new() + .spacing(5) + .push(text("can recover")) + .push(text(format!( + "{} coin{} totalling", + number_of_coins, + if number_of_coins > 0 { "s" } else { "" } + ))) + .push(amount(&total_amount)), + ), + ) + .align_items(Alignment::Center) + .spacing(20), ) .style(theme::Container::Card(theme::Card::Simple)) .width(Length::Fill) diff --git a/gui/src/app/view/transactions.rs b/gui/src/app/view/transactions.rs index 5da5a9e8..dac6b070 100644 --- a/gui/src/app/view/transactions.rs +++ b/gui/src/app/view/transactions.rs @@ -91,6 +91,8 @@ fn tx_list_view<'a>(i: usize, tx: &HistoryTransaction) -> Element<'a, Message> { Row::new() .push(if tx.is_external() { badge::receive() + } else if tx.is_self_send() { + badge::cycle() } else { badge::spend() }) diff --git a/gui/ui/src/component/badge.rs b/gui/ui/src/component/badge.rs index c8c44382..ac3d77f2 100644 --- a/gui/ui/src/component/badge.rs +++ b/gui/ui/src/component/badge.rs @@ -43,6 +43,15 @@ pub fn receive() -> Container<'static, T> { .center_y() } +pub fn cycle() -> Container<'static, T> { + Container::new(icon::arrow_repeat().width(Length::Units(20))) + .width(Length::Units(40)) + .height(Length::Units(40)) + .style(theme::Container::Badge(theme::Badge::Standard)) + .center_x() + .center_y() +} + pub fn spend() -> Container<'static, T> { Container::new(icon::send_icon().width(Length::Units(20))) .width(Length::Units(40)) diff --git a/gui/ui/src/component/button.rs b/gui/ui/src/component/button.rs index 391a3318..21a1528a 100644 --- a/gui/ui/src/component/button.rs +++ b/gui/ui/src/component/button.rs @@ -1,15 +1,17 @@ -use crate::{theme, widget::*}; +use crate::{color, theme, widget::*}; use iced::widget::{button, container, row}; use iced::{Alignment, Length}; use super::text::text; pub fn menu<'a, T: 'a>(icon: Option>, t: &'static str) -> Button<'a, T> { - button::Button::new(content(icon, t).padding(10)).style(theme::Button::Menu(false)) + button::Button::new(content(icon.map(|i| i.style(color::GREY_3)), t).padding(10)) + .style(theme::Button::Menu(false)) } pub fn menu_active<'a, T: 'a>(icon: Option>, t: &'static str) -> Button<'a, T> { - button::Button::new(content(icon, t).padding(10)).style(theme::Button::Menu(true)) + button::Button::new(content(icon.map(|i| i.style(color::GREY_3)), t).padding(10)) + .style(theme::Button::Menu(true)) } pub fn alert<'a, T: 'a>(icon: Option>, t: &'static str) -> Button<'a, T> { diff --git a/gui/ui/src/component/card.rs b/gui/ui/src/component/card.rs index 7877a05f..7b6e8500 100644 --- a/gui/ui/src/component/card.rs +++ b/gui/ui/src/component/card.rs @@ -18,7 +18,7 @@ pub fn warning<'a, T: 'a>(message: String) -> Container<'a, T> { Row::new() .spacing(20) .align_items(iced::Alignment::Center) - .push(icon::warning_octagon_icon()) + .push(icon::warning_icon()) .push(text(message)), ) .padding(15) diff --git a/gui/ui/src/icon.rs b/gui/ui/src/icon.rs index 3337bb19..050ca1e9 100644 --- a/gui/ui/src/icon.rs +++ b/gui/ui/src/icon.rs @@ -1,245 +1,180 @@ use crate::widget::*; use iced::{alignment, Font, Length}; -const ICONS: Font = Font::External { - name: "Icons", +const BOOTSTRAP_ICONS: Font = Font::External { + name: "Bootstrap icons", bytes: include_bytes!("../static/icons/bootstrap-icons.ttf"), }; -fn icon(unicode: char) -> Text<'static> { +fn bootstrap_icon(unicode: char) -> Text<'static> { Text::new(unicode.to_string()) - .font(ICONS) + .font(BOOTSTRAP_ICONS) .width(Length::Units(20)) .horizontal_alignment(alignment::Horizontal::Center) .size(20) } +pub fn cross_icon() -> Text<'static> { + bootstrap_icon('\u{F62A}') +} + pub fn arrow_down() -> Text<'static> { - icon('\u{F128}') + bootstrap_icon('\u{F128}') } pub fn arrow_right() -> Text<'static> { - icon('\u{F138}') -} - -pub fn arrow_repeat() -> Text<'static> { - icon('\u{F130}') + bootstrap_icon('\u{F138}') } pub fn arrow_return_right() -> Text<'static> { - icon('\u{F132}') + bootstrap_icon('\u{F132}') } pub fn chevron_right() -> Text<'static> { - icon('\u{F285}') + bootstrap_icon('\u{F285}') } pub fn recovery_icon() -> Text<'static> { - icon('\u{F467}') + bootstrap_icon('\u{F467}') } pub fn plug_icon() -> Text<'static> { - icon('\u{F4F6}') + bootstrap_icon('\u{F4F6}') } pub fn reload_icon() -> Text<'static> { - icon('\u{F130}') + bootstrap_icon('\u{F130}') } pub fn import_icon() -> Text<'static> { - icon('\u{F30A}') + bootstrap_icon('\u{F30A}') } pub fn wallet_icon() -> Text<'static> { - icon('\u{F615}') -} - -pub fn hourglass_icon() -> Text<'static> { - icon('\u{F41F}') -} - -pub fn hourglass_done_icon() -> Text<'static> { - icon('\u{F41E}') -} - -pub fn vault_icon() -> Text<'static> { - icon('\u{F65A}') + bootstrap_icon('\u{F615}') } pub fn bitcoin_icon() -> Text<'static> { - icon('\u{F635}') -} - -pub fn history_icon() -> Text<'static> { - icon('\u{F292}') -} - -pub fn home_icon() -> Text<'static> { - icon('\u{F3FC}') -} - -pub fn unlock_icon() -> Text<'static> { - icon('\u{F600}') -} - -pub fn warning_octagon_icon() -> Text<'static> { - icon('\u{F337}') -} - -pub fn send_icon() -> Text<'static> { - icon('\u{F144}') -} - -pub fn connect_device_icon() -> Text<'static> { - icon('\u{F348}') -} - -pub fn connected_device_icon() -> Text<'static> { - icon('\u{F350}') -} - -pub fn receive_icon() -> Text<'static> { - icon('\u{F123}') -} - -pub fn calendar_icon() -> Text<'static> { - icon('\u{F1E8}') -} - -pub fn turnback_icon() -> Text<'static> { - icon('\u{F131}') -} - -pub fn vaults_icon() -> Text<'static> { - icon('\u{F1C7}') -} - -pub fn coin_icon() -> Text<'static> { - icon('\u{F567}') -} - -pub fn settings_icon() -> Text<'static> { - icon('\u{F3E5}') + bootstrap_icon('\u{F635}') } pub fn block_icon() -> Text<'static> { - icon('\u{F1C8}') -} - -pub fn square_icon() -> Text<'static> { - icon('\u{F584}') -} - -pub fn square_check_icon() -> Text<'static> { - icon('\u{F26D}') -} - -pub fn circle_check_icon() -> Text<'static> { - icon('\u{F26B}') -} - -pub fn circle_cross_icon() -> Text<'static> { - icon('\u{F623}') -} - -pub fn network_icon() -> Text<'static> { - icon('\u{F40D}') + bootstrap_icon('\u{F1C8}') } pub fn dot_icon() -> Text<'static> { - icon('\u{F287}') -} - -pub fn clipboard_icon() -> Text<'static> { - icon('\u{F3C2}') -} - -pub fn shield_icon() -> Text<'static> { - icon('\u{F53F}') -} - -pub fn shield_notif_icon() -> Text<'static> { - icon('\u{F530}') -} - -pub fn shield_check_icon() -> Text<'static> { - icon('\u{F52F}') -} - -pub fn person_check_icon() -> Text<'static> { - icon('\u{F4D6}') + bootstrap_icon('\u{F287}') } pub fn person_icon() -> Text<'static> { - icon('\u{F4DA}') + bootstrap_icon('\u{F4DA}') } pub fn tooltip_icon() -> Text<'static> { - icon('\u{F431}') + bootstrap_icon('\u{F431}') } pub fn plus_icon() -> Text<'static> { - icon('\u{F4FE}') + bootstrap_icon('\u{F4FE}') } pub fn warning_icon() -> Text<'static> { - icon('\u{F33B}') + bootstrap_icon('\u{F33B}') } pub fn chip_icon() -> Text<'static> { - icon('\u{F2D6}') + bootstrap_icon('\u{F2D6}') } pub fn trash_icon() -> Text<'static> { - icon('\u{F5DE}') -} - -pub fn key_icon() -> Text<'static> { - icon('\u{F44F}') -} - -pub fn cross_icon() -> Text<'static> { - icon('\u{F62A}') + bootstrap_icon('\u{F5DE}') } pub fn pencil_icon() -> Text<'static> { - icon('\u{F4CB}') -} - -#[allow(dead_code)] -pub fn stakeholder_icon() -> Text<'static> { - icon('\u{F4AE}') -} - -#[allow(dead_code)] -pub fn manager_icon() -> Text<'static> { - icon('\u{F4B4}') -} - -pub fn done_icon() -> Text<'static> { - icon('\u{F26B}') -} - -pub fn todo_icon() -> Text<'static> { - icon('\u{F28A}') + bootstrap_icon('\u{F4CB}') } pub fn collapse_icon() -> Text<'static> { - icon('\u{F284}') + bootstrap_icon('\u{F284}') } pub fn collapsed_icon() -> Text<'static> { - icon('\u{F282}') + bootstrap_icon('\u{F282}') } pub fn down_icon() -> Text<'static> { - icon('\u{F279}') + bootstrap_icon('\u{F279}') } pub fn up_icon() -> Text<'static> { - icon('\u{F27C}') + bootstrap_icon('\u{F27C}') } pub fn people_icon() -> Text<'static> { - icon('\u{F4CF}') + bootstrap_icon('\u{F4CF}') +} + +pub fn network_icon() -> Text<'static> { + bootstrap_icon('\u{F40D}') +} + +const ICONEX_ICONS: Font = Font::External { + name: "Iconex icons", + bytes: include_bytes!("../static/icons/iconex/iconex-icons.ttf"), +}; + +fn iconex_icon(unicode: char) -> Text<'static> { + Text::new(unicode.to_string()) + .font(ICONEX_ICONS) + .width(Length::Units(20)) + .horizontal_alignment(alignment::Horizontal::Center) + .size(20) +} + +pub fn arrow_repeat() -> Text<'static> { + iconex_icon('\u{46BB}') +} + +pub fn send_icon() -> Text<'static> { + iconex_icon('\u{2CEE}') +} + +pub fn receive_icon() -> Text<'static> { + iconex_icon('\u{605B}') +} + +pub fn home_icon() -> Text<'static> { + iconex_icon('\u{C722}') +} + +pub fn settings_icon() -> Text<'static> { + iconex_icon('\u{3038}') +} + +pub fn key_icon() -> Text<'static> { + iconex_icon('\u{FFEC}') +} + +pub fn history_icon() -> Text<'static> { + iconex_icon('\u{BEBA}') +} + +pub fn coins_icon() -> Text<'static> { + iconex_icon('\u{9F25}') +} + +pub fn clock_icon() -> Text<'static> { + iconex_icon('\u{B0CA}') +} + +pub fn clipboard_icon() -> Text<'static> { + iconex_icon('\u{F8D3}') +} + +pub fn circle_check_icon() -> Text<'static> { + iconex_icon('\u{E2F9}') +} + +pub fn circle_cross_icon() -> Text<'static> { + iconex_icon('\u{19DA}') } diff --git a/gui/ui/src/image.rs b/gui/ui/src/image.rs index 0403e7e8..55783f6a 100644 --- a/gui/ui/src/image.rs +++ b/gui/ui/src/image.rs @@ -12,27 +12,3 @@ pub fn liana_grey_logo() -> Svg { let h = Handle::from_memory(LIANA_LOGO_GREY.to_vec()); Svg::new(h) } - -const HISTORY_ICON: &[u8] = include_bytes!("../static/icons/history-icon.svg"); -pub fn history_icon() -> Svg { - let h = Handle::from_memory(HISTORY_ICON.to_vec()); - Svg::new(h) -} - -const COINS_ICON: &[u8] = include_bytes!("../static/icons/coins-icon.svg"); -pub fn coins_icon() -> Svg { - let h = Handle::from_memory(COINS_ICON.to_vec()); - Svg::new(h) -} - -const CLOCK_ICON: &[u8] = include_bytes!("../static/icons/clock-icon.svg"); -pub fn clock_icon() -> Svg { - let h = Handle::from_memory(CLOCK_ICON.to_vec()); - Svg::new(h) -} - -const CLOCK_RED_ICON: &[u8] = include_bytes!("../static/icons/clock-red-icon.svg"); -pub fn clock_red_icon() -> Svg { - let h = Handle::from_memory(CLOCK_RED_ICON.to_vec()); - Svg::new(h) -} diff --git a/gui/ui/static/icons/clock-icon.svg b/gui/ui/static/icons/clock-icon.svg deleted file mode 100644 index a8a6e077..00000000 --- a/gui/ui/static/icons/clock-icon.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/gui/ui/static/icons/clock-red-icon.svg b/gui/ui/static/icons/clock-red-icon.svg deleted file mode 100644 index ccc387cc..00000000 --- a/gui/ui/static/icons/clock-red-icon.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/gui/ui/static/icons/coins-icon.svg b/gui/ui/static/icons/coins-icon.svg deleted file mode 100644 index 5abe3a3b..00000000 --- a/gui/ui/static/icons/coins-icon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gui/ui/static/icons/iconex/iconex-icons.ttf b/gui/ui/static/icons/iconex/iconex-icons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1510d962fff5eee37b8a39e4941dc4cdaf273262 GIT binary patch literal 7608 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 B=raHS literal 0 HcmV?d00001 diff --git a/gui/ui/static/icons/iconex/svg/IconBack.svg b/gui/ui/static/icons/iconex/svg/IconBack.svg new file mode 100644 index 00000000..7243abf0 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconBack.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconBroadcast.svg b/gui/ui/static/icons/iconex/svg/IconBroadcast.svg new file mode 100644 index 00000000..6f6cad21 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconBroadcast.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconCheck.svg b/gui/ui/static/icons/iconex/svg/IconCheck.svg new file mode 100644 index 00000000..8bc9413a --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconCheck.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconClear.svg b/gui/ui/static/icons/iconex/svg/IconClear.svg new file mode 100644 index 00000000..cb0b283c --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconClear.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconCoins.svg b/gui/ui/static/icons/iconex/svg/IconCoins.svg new file mode 100644 index 00000000..070bce92 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconCoins.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/ui/static/icons/iconex/svg/IconCopy.svg b/gui/ui/static/icons/iconex/svg/IconCopy.svg new file mode 100644 index 00000000..bca0ee1d --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconCopy.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconDown.svg b/gui/ui/static/icons/iconex/svg/IconDown.svg new file mode 100644 index 00000000..7143a3af --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconDown.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/ui/static/icons/history-icon.svg b/gui/ui/static/icons/iconex/svg/IconHistory.svg similarity index 100% rename from gui/ui/static/icons/history-icon.svg rename to gui/ui/static/icons/iconex/svg/IconHistory.svg diff --git a/gui/ui/static/icons/iconex/svg/IconHome.svg b/gui/ui/static/icons/iconex/svg/IconHome.svg new file mode 100644 index 00000000..d2ff0c8f --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconHome.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconImport.svg b/gui/ui/static/icons/iconex/svg/IconImport.svg new file mode 100644 index 00000000..55416a3b --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconImport.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconKey.svg b/gui/ui/static/icons/iconex/svg/IconKey.svg new file mode 100644 index 00000000..430b91f8 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconKey.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconPlus.svg b/gui/ui/static/icons/iconex/svg/IconPlus.svg new file mode 100644 index 00000000..4f5d2b82 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconPlus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconReceive.svg b/gui/ui/static/icons/iconex/svg/IconReceive.svg new file mode 100644 index 00000000..a09c9028 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconReceive.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconRefresh.svg b/gui/ui/static/icons/iconex/svg/IconRefresh.svg new file mode 100644 index 00000000..cdca4b9b --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconRefresh.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/ui/static/icons/iconex/svg/IconSablier.svg b/gui/ui/static/icons/iconex/svg/IconSablier.svg new file mode 100644 index 00000000..e660e1df --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconSablier.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconSave.svg b/gui/ui/static/icons/iconex/svg/IconSave.svg new file mode 100644 index 00000000..63c9958d --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconSave.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconSend.svg b/gui/ui/static/icons/iconex/svg/IconSend.svg new file mode 100644 index 00000000..31d82206 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconSend.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconTime.svg b/gui/ui/static/icons/iconex/svg/IconTime.svg new file mode 100644 index 00000000..15d2c0fe --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconTime.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/ui/static/icons/iconex/svg/IconeSettings.svg b/gui/ui/static/icons/iconex/svg/IconeSettings.svg new file mode 100644 index 00000000..e52b2376 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg/IconeSettings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/ui/static/icons/iconex/svg_to_ttf.py b/gui/ui/static/icons/iconex/svg_to_ttf.py new file mode 100644 index 00000000..27eda859 --- /dev/null +++ b/gui/ui/static/icons/iconex/svg_to_ttf.py @@ -0,0 +1,33 @@ +import sys +import os +import fontforge + + +def generate_glyph_code(filename): + glyph_code = hash(filename) % 0xFFFF + + # Avoid surrogate range (0xD800-0xDFFF) + if 0xD800 <= glyph_code <= 0xDFFF: + glyph_code += 0x800 + + return glyph_code + + +input_folder = sys.argv[1] +output_font_file = sys.argv[2] + +font = fontforge.font() +font.encoding = 'UnicodeFull' + +for svg_file in os.listdir(input_folder): + if not svg_file.endswith('.svg'): + continue + + glyph_name = os.path.splitext(svg_file)[0] + glyph_code = generate_glyph_code(glyph_name) + + glyph = font.createChar(glyph_code) + glyph.importOutlines(os.path.join(input_folder, svg_file)) + glyph.simplify() + +font.generate(output_font_file) From 3f8f4cec92b445d4c9cc453873f7c474090df5fc Mon Sep 17 00:00:00 2001 From: edouard Date: Tue, 9 May 2023 16:45:49 +0200 Subject: [PATCH 2/7] fix: recovery layout --- gui/src/app/state/recovery.rs | 51 ++++--- gui/src/app/view/recovery.rs | 250 +++++++++++++++++++--------------- 2 files changed, 162 insertions(+), 139 deletions(-) diff --git a/gui/src/app/state/recovery.rs b/gui/src/app/state/recovery.rs index 7d62568b..cd90a24f 100644 --- a/gui/src/app/state/recovery.rs +++ b/gui/src/app/state/recovery.rs @@ -54,34 +54,31 @@ impl State for RecoveryPanel { if let Some(generated) = &self.generated { generated.view(cache) } else { - view::modal( - false, + view::recovery::recovery( + cache, + self.recovery_paths + .iter() + .enumerate() + .filter_map(|(i, path)| { + if path.number_of_coins > 0 { + Some(view::recovery::recovery_path_view( + i, + path.threshold, + &path.origins, + path.total_amount, + path.number_of_coins, + &self.wallet.keys_aliases, + self.selected_path == Some(i), + )) + } else { + None + } + }) + .collect(), + self.selected_path, + &self.feerate, + &self.recipient, self.warning.as_ref(), - view::recovery::recovery( - self.recovery_paths - .iter() - .enumerate() - .filter_map(|(i, path)| { - if path.number_of_coins > 0 { - Some(view::recovery::recovery_path_view( - i, - path.threshold, - &path.origins, - path.total_amount, - path.number_of_coins, - &self.wallet.keys_aliases, - self.selected_path == Some(i), - )) - } else { - None - } - }) - .collect(), - self.selected_path, - &self.feerate, - &self.recipient, - ), - None::>, ) } } diff --git a/gui/src/app/view/recovery.rs b/gui/src/app/view/recovery.rs index fe7ce4d0..96ef4ac7 100644 --- a/gui/src/app/view/recovery.rs +++ b/gui/src/app/view/recovery.rs @@ -17,48 +17,53 @@ use liana_ui::{ widget::*, }; -use crate::app::view::message::{CreateSpendMessage, Message}; +use crate::app::{ + cache::Cache, + menu::Menu, + view::{ + dashboard, + message::{CreateSpendMessage, Message}, + }, + Error, +}; #[allow(clippy::too_many_arguments)] pub fn recovery<'a>( + cache: &'a Cache, recovery_paths: Vec>, selected_path: Option, feerate: &form::Value, address: &'a form::Value, + warning: Option<&Error>, ) -> Element<'a, Message> { let no_recovery_paths = recovery_paths.is_empty(); - Column::new() - .push(Space::with_height(Length::Units(100))) - .push( - Row::new() - .push(Container::new( - icon::recovery_icon().width(Length::Units(100)).size(50), - )) - .push(text("Recover the funds").size(50).bold()) - .align_items(Alignment::Center) - .spacing(1), - ) - .push(if no_recovery_paths { - Container::new(text("No recovery path is currently available")) - } else { - Container::new( - Column::new() + dashboard( + &Menu::Settings, + cache, + warning, + Column::new() + .push( + Row::new() .spacing(10) - .push(text(format!( - "{} recovery paths will be available at the next block, select one:", - recovery_paths.len() - ))) - .push(Column::with_children(recovery_paths).spacing(10)), + .align_items(Alignment::Center) + .push( + Button::new(text("Settings").size(30).bold()) + .style(theme::Button::Transparent) + .on_press(Message::Menu(Menu::Settings)), + ) + .push(icon::chevron_right().size(30)) + .push( + Button::new(text("Recovery").size(30).bold()) + .style(theme::Button::Transparent) + .on_press(Message::Menu(Menu::Recovery)), + ), ) - .padding(20) - }) - .push(Space::with_height(Length::Units(20))) - .push_maybe(if no_recovery_paths { - None - } else { - Some( - Column::new() - .push(text("Enter destination address and feerate:").bold()) + .push(Space::with_height(Length::Units(20))) + .push( + Row::new() + .spacing(20) + .align_items(Alignment::Center) + .push(text("Destination").bold()) .push( Container::new( form::Form::new("Address", address, move |msg| { @@ -70,8 +75,10 @@ pub fn recovery<'a>( .size(20) .padding(10), ) - .width(Length::Units(250)), + .max_width(500) + .width(Length::Fill), ) + .push(text("Feerate").bold()) .push( Container::new( form::Form::new("42 (sats/vbyte)", feerate, move |msg| { @@ -81,29 +88,50 @@ pub fn recovery<'a>( .size(20) .padding(10), ) - .width(Length::Units(250)), - ) - .push( - if feerate.valid - && !feerate.value.is_empty() - && address.valid - && !address.value.is_empty() - && selected_path.is_some() - { - button::primary(None, "Next") - .on_press(Message::Next) - .width(Length::Units(200)) - } else { - button::primary(None, "Next").width(Length::Units(200)) - }, - ) - .spacing(20) - .align_items(Alignment::Center), + .width(Length::Units(200)), + ), ) - }) - .align_items(Alignment::Center) - .spacing(20) - .into() + .push(if no_recovery_paths { + Container::new(text("No recovery path is currently available")) + } else { + Container::new( + Column::new() + .spacing(20) + .push(text(format!( + "{} recovery paths will be available at the next block, select one:", + recovery_paths.len() + ))) + .push(Column::with_children(recovery_paths).spacing(20)), + ) + .style(theme::Container::Card(theme::Card::Simple)) + .padding(20) + }) + .push_maybe(if no_recovery_paths { + None + } else { + Some( + Row::new() + .push(Space::with_width(Length::Fill)) + .push( + if feerate.valid + && !feerate.value.is_empty() + && address.valid + && !address.value.is_empty() + && selected_path.is_some() + { + button::primary(None, "Next") + .on_press(Message::Next) + .width(Length::Units(200)) + } else { + button::primary(None, "Next").width(Length::Units(200)) + }, + ) + .spacing(20) + .align_items(Alignment::Center), + ) + }) + .spacing(20), + ) } pub fn recovery_path_view<'a>( @@ -115,63 +143,61 @@ pub fn recovery_path_view<'a>( key_aliases: &'a HashMap, selected: bool, ) -> Element<'a, Message> { - Container::new( - Row::new() - .push(checkbox("", selected, move |_| { - Message::CreateSpend(CreateSpendMessage::SelectPath(index)) - })) - .push( - Column::new() - .push( - Row::new() - .align_items(Alignment::Center) - .spacing(10) - .push( - text(format!( - "{} signature{} from", - threshold, - if threshold > 1 { "s" } else { "" } - )) - .bold(), - ) - .push(origins.iter().fold( - Row::new().align_items(Alignment::Center).spacing(5), - |row, (fg, _)| { - row.push(if let Some(alias) = key_aliases.get(fg) { - Container::new( - tooltip::Tooltip::new( - Container::new(text(alias)).padding(3).style( - theme::Container::Pill(theme::Pill::Simple), - ), - fg.to_string(), - tooltip::Position::Bottom, - ) - .style(theme::Container::Card(theme::Card::Simple)), + Row::new() + .push(checkbox("", selected, move |_| { + Message::CreateSpend(CreateSpendMessage::SelectPath(index)) + })) + .push( + Column::new() + .push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push( + text(format!( + "{} signature{} from", + threshold, + if threshold > 1 { "s" } else { "" } + )) + .bold(), + ) + .push(origins.iter().fold( + Row::new().align_items(Alignment::Center).spacing(5), + |row, (fg, _)| { + row.push(if let Some(alias) = key_aliases.get(fg) { + Container::new( + tooltip::Tooltip::new( + Container::new(text(alias)) + .padding(5) + .style(theme::Container::Pill(theme::Pill::Simple)), + fg.to_string(), + tooltip::Position::Bottom, ) - } else { - Container::new(text(fg.to_string())) - .padding(3) - .style(theme::Container::Pill(theme::Pill::Simple)) - }) - }, - )), - ) - .push( - Row::new() - .spacing(5) - .push(text("can recover")) - .push(text(format!( - "{} coin{} totalling", - number_of_coins, - if number_of_coins > 0 { "s" } else { "" } - ))) - .push(amount(&total_amount)), - ), - ) - .align_items(Alignment::Center) - .spacing(20), - ) - .style(theme::Container::Card(theme::Card::Simple)) - .width(Length::Fill) - .into() + .style(theme::Container::Card(theme::Card::Simple)), + ) + } else { + Container::new(text(fg.to_string())) + .padding(5) + .style(theme::Container::Pill(theme::Pill::Simple)) + }) + }, + )), + ) + .push( + Row::new() + .spacing(5) + .push(text("can recover")) + .push(text(format!( + "{} coin{} totalling", + number_of_coins, + if number_of_coins > 0 { "s" } else { "" } + ))) + .push(amount(&total_amount)), + ) + .spacing(5), + ) + .width(Length::Fill) + .align_items(Alignment::Center) + .spacing(20) + .into() } From cf042316c12a935c6d971bb150006afd15f310c4 Mon Sep 17 00:00:00 2001 From: edouard Date: Tue, 9 May 2023 18:22:52 +0200 Subject: [PATCH 3/7] fix: installer layout --- gui/src/installer/step/descriptor.rs | 1 + gui/src/installer/view.rs | 166 ++++++++++++++------------- gui/ui/src/icon.rs | 4 + gui/ui/src/theme.rs | 2 +- 4 files changed, 91 insertions(+), 82 deletions(-) diff --git a/gui/src/installer/step/descriptor.rs b/gui/src/installer/step/descriptor.rs index 296da64e..88ca8cfe 100644 --- a/gui/src/installer/step/descriptor.rs +++ b/gui/src/installer/step/descriptor.rs @@ -197,6 +197,7 @@ impl DefineDescriptor { for path in &mut self.recovery_paths { path.duplicate_sequence = duplicate_sequence.contains(&path.sequence); for recovery_key in path.keys.iter_mut() { + recovery_key.duplicate_name = duplicate_names.contains(&recovery_key.name); if let Some(key) = &recovery_key.key { recovery_key.duplicate_key = duplicate_keys.contains(key); } diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index cb4e4de2..86e60142 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -10,7 +10,7 @@ use liana_ui::{ color, component::{ button, card, collapse, form, hw, separation, - text::{text, Text}, + text::{h3, text, Text}, tooltip, }, icon, theme, @@ -147,10 +147,9 @@ pub fn define_descriptor<'a>( valid: bool, error: Option<&String>, ) -> Element<'a, Message> { - let row_network = Row::new() + let col_network = Column::new() .spacing(10) - .align_items(Alignment::Center) - .push(text("Network:").bold()) + .push(text("Network").bold()) .push(container( pick_list(&NETWORKS[..], Some(Network::from(network)), |net| { Message::Network(net.into()) @@ -166,14 +165,12 @@ pub fn define_descriptor<'a>( None } else { Some(text("A data directory already exists for this network").style(color::RED)) - }) - .padding(50); + }); let col_spending_keys = Column::new() .push( Row::new() .spacing(10) - .push(Space::with_width(Length::Units(5))) .push(text("Primary path:").bold()) .push(tooltip(prompt::DEFINE_DESCRIPTOR_PRIMARY_PATH_TOOLTIP)), ) @@ -227,14 +224,12 @@ pub fn define_descriptor<'a>( layout( progress, + "Create the wallet", Column::new() - .push(Space::with_height(Length::Units(30))) - .push(text("Create the wallet").bold().size(50)) .push( Column::new() .width(Length::Fill) - .align_items(Alignment::Center) - .push(row_network) + .push(col_network) .push( Column::new() .spacing(25) @@ -242,7 +237,6 @@ pub fn define_descriptor<'a>( .push( Row::new() .spacing(10) - .push(Space::with_width(Length::Units(5))) .push(text("Recovery paths:").bold()) .push(tooltip(prompt::DEFINE_DESCRIPTOR_RECOVERY_PATH_TOOLTIP)), ) @@ -253,9 +247,13 @@ pub fn define_descriptor<'a>( .push( Row::new() .spacing(10) - .push(button::secondary(None, "Add a recovery path").on_press( - Message::DefineDescriptor(message::DefineDescriptor::AddRecoveryPath), - )) + .push( + button::secondary(Some(icon::plus_icon()), "Add a recovery path") + .on_press(Message::DefineDescriptor( + message::DefineDescriptor::AddRecoveryPath, + )) + .width(Length::Units(200)), + ) .push(if !valid { button::primary(None, "Next").width(Length::Units(200)) } else { @@ -268,8 +266,8 @@ pub fn define_descriptor<'a>( .push(Space::with_height(Length::Units(20))) .width(Length::Fill) .height(Length::Fill) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + false, ) } @@ -365,8 +363,8 @@ pub fn import_descriptor<'a>( .spacing(10); layout( progress, + "Import the wallet", Column::new() - .push(text("Import the wallet").bold().size(50)) .push( Column::new() .spacing(20) @@ -385,11 +383,8 @@ pub fn import_descriptor<'a>( .on_press(Message::Next) }) .push_maybe(error.map(|e| card::error("Invalid descriptor", e.to_string()))) - .width(Length::Fill) - .height(Length::Fill) - .padding(100) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + true, ) } @@ -579,8 +574,8 @@ pub fn participate_xpub<'a>( layout( progress, + "Share your public keys", Column::new() - .push(text("Share your public keys").bold().size(50)) .push( Column::new() .spacing(20) @@ -619,11 +614,8 @@ pub fn participate_xpub<'a>( } else { button::primary(None, "Next").width(Length::Units(200)) }) - .width(Length::Fill) - .height(Length::Fill) - .padding(100) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + true ) } @@ -640,9 +632,8 @@ pub fn register_descriptor<'a>( ) -> Element<'a, Message> { layout( progress, + "Register descriptor", Column::new() - .max_width(1000) - .push(text("Register descriptor").bold().size(50)) .push(card::simple( Column::new() .push(text("The descriptor:").small().bold()) @@ -705,11 +696,8 @@ pub fn register_descriptor<'a>( } else { button::primary(None, "Next").width(Length::Units(200)) }) - .width(Length::Fill) - .height(Length::Fill) - .padding(100) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + true, ) } @@ -720,12 +708,8 @@ pub fn backup_descriptor<'a>( ) -> Element<'a, Message> { layout( progress, + "Backup your wallet descriptor", Column::new() - .push( - text("Did you backup your wallet descriptor ?") - .bold() - .size(50), - ) .push( Column::new() .push(text(prompt::BACKUP_DESCRIPTOR_MESSAGE)) @@ -779,11 +763,8 @@ pub fn backup_descriptor<'a>( } else { button::primary(None, "Next").width(Length::Units(200)) }) - .width(Length::Fill) - .height(Length::Fill) - .padding(100) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + true, ) } @@ -823,12 +804,8 @@ pub fn define_bitcoin<'a>( layout( progress, + "Set up connection to the Bitcoin full node", Column::new() - .push( - text("Set up connection to the Bitcoin full node") - .bold() - .size(50), - ) .push(col_address) .push(col_cookie) .push_maybe(if is_running.is_some() { @@ -872,11 +849,8 @@ pub fn define_bitcoin<'a>( button::primary(None, "Next").width(Length::Units(200)) }), ) - .width(Length::Fill) - .height(Length::Fill) - .padding(100) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + true, ) } @@ -891,10 +865,8 @@ pub fn install<'a>( ) -> Element<'a, Message> { layout( progress, + "Final step", Column::new() - .push(Space::with_height(Length::Units(50))) - .push(text("Final step").bold().size(50)) - .push(Space::with_height(Length::Units(50))) .push(text( "Check your information before finalizing the install process:", )) @@ -1036,8 +1008,8 @@ pub fn install<'a>( }) .spacing(10) .width(Length::Fill) - .height(Length::Fill) - .align_items(Alignment::Center), + .height(Length::Fill), + true, ) } @@ -1121,7 +1093,12 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> { Column::new() .spacing(15) .align_items(Alignment::Center) - .push(icon::key_icon().size(30).width(Length::Units(50))), + .push( + icon::key_icon() + .size(30) + .width(Length::Units(50)) + .style(color::GREY_3), + ), ) .height(Length::Fill) .align_y(alignment::Vertical::Center), @@ -1526,8 +1503,8 @@ pub fn backup_mnemonic<'a>( ) -> Element<'a, Message> { layout( progress, + "Backup your mnemonic", Column::new() - .push(text("Backup your mnemonic").bold().size(50)) .push(text(prompt::MNEMONIC_HELP)) .push( words @@ -1557,11 +1534,8 @@ pub fn backup_mnemonic<'a>( } else { button::primary(None, "Next").width(Length::Units(200)) }) - .width(Length::Fill) - .height(Length::Fill) - .padding(100) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + true, ) } @@ -1575,8 +1549,8 @@ pub fn recover_mnemonic<'a>( ) -> Element<'a, Message> { layout( progress, + "Import Mnemonic", Column::new() - .push(text("Mnemonics import").bold().size(50)) .push(text(prompt::RECOVER_MNEMONIC_HELP)) .push_maybe(if recover { Some( @@ -1662,30 +1636,60 @@ pub fn recover_mnemonic<'a>( }, ) }) - .width(Length::Fill) - .height(Length::Fill) - .padding(100) - .spacing(50) - .align_items(Alignment::Center), + .spacing(50), + true, ) } fn layout<'a>( progress: (usize, usize), + title: &'static str, content: impl Into>, + padding_left: bool, ) -> Element<'a, Message> { Container::new(scrollable( Column::new() + .width(Length::Fill) + .push(Space::with_height(Length::Units(100))) .push( - Container::new(button::transparent(None, "< Previous").on_press(Message::Previous)) - .padding(5), + Row::new() + .align_items(Alignment::Center) + .push( + Container::new( + button::transparent(Some(icon::previous_icon()), "Previous") + .on_press(Message::Previous), + ) + .width(Length::FillPortion(2)) + .center_x(), + ) + .push(Container::new(h3(title)).width(Length::FillPortion(8))) + .push( + Container::new(text(format!("{} | {}", progress.0, progress.1))) + .width(Length::FillPortion(2)) + .center_x(), + ), ) .push( - Container::new(text(format!("{}/{}", progress.0, progress.1))) - .width(Length::Fill) - .center_x(), - ) - .push(Container::new(content).width(Length::Fill).center_x()), + Row::new() + .push(Space::with_width(Length::FillPortion(2))) + .push( + Container::new( + Column::new() + .push(Space::with_height(Length::Units(100))) + .push(content), + ) + .width(Length::FillPortion(if padding_left { + 8 + } else { + 10 + })), + ) + .push_maybe(if padding_left { + Some(Space::with_width(Length::FillPortion(2))) + } else { + None + }), + ), )) .center_x() .height(Length::Fill) diff --git a/gui/ui/src/icon.rs b/gui/ui/src/icon.rs index 050ca1e9..756de529 100644 --- a/gui/ui/src/icon.rs +++ b/gui/ui/src/icon.rs @@ -118,6 +118,10 @@ pub fn network_icon() -> Text<'static> { bootstrap_icon('\u{F40D}') } +pub fn previous_icon() -> Text<'static> { + bootstrap_icon('\u{F284}') +} + const ICONEX_ICONS: Font = Font::External { name: "Iconex icons", bytes: include_bytes!("../static/icons/iconex/iconex-icons.ttf"), diff --git a/gui/ui/src/theme.rs b/gui/ui/src/theme.rs index 5c806362..184fb017 100644 --- a/gui/ui/src/theme.rs +++ b/gui/ui/src/theme.rs @@ -413,7 +413,7 @@ impl pick_list::StyleSheet for Theme { border_width: 1.0, border_color: color::RED, border_radius: 25.0, - text_color: iced::Color::BLACK, + text_color: color::RED, }, } } From e0a207bb06460b03df17b0d61c131ecc9dceeb42 Mon Sep 17 00:00:00 2001 From: edouard Date: Tue, 9 May 2023 20:57:19 +0200 Subject: [PATCH 4/7] installer: change user path icons --- gui/src/installer/view.rs | 80 +++++++++++++++++------------- gui/ui/src/icon.rs | 4 -- gui/ui/src/image.rs | 21 ++++++++ gui/ui/static/icons/blueprint.svg | 12 +++++ gui/ui/static/icons/discussion.svg | 4 ++ gui/ui/static/icons/syncdata.svg | 5 ++ 6 files changed, 87 insertions(+), 39 deletions(-) create mode 100644 gui/ui/static/icons/blueprint.svg create mode 100644 gui/ui/static/icons/discussion.svg create mode 100644 gui/ui/static/icons/syncdata.svg diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index 86e60142..71862925 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -10,10 +10,10 @@ use liana_ui::{ color, component::{ button, card, collapse, form, hw, separation, - text::{h3, text, Text}, + text::{h3, p1_regular, text, Text}, tooltip, }, - icon, theme, + icon, image, theme, util::Collection, widget::*, }; @@ -80,48 +80,58 @@ pub fn welcome<'a>() -> Element<'a, Message> { Column::new() .push( Row::new() + .align_items(Alignment::End) .spacing(20) .push( - Button::new( - Container::new( - Column::new() - .width(Length::Units(250)) - .push(icon::wallet_icon().size(50).width(Length::Units(100))) - .push(text("Create a new wallet")) - .align_items(Alignment::Center), - ) - .padding(20), + Container::new( + Column::new() + .spacing(20) + .align_items(Alignment::Center) + .push(image::create_new_wallet_icon().width(Length::Units(100))) + .push(p1_regular("Create a new wallet").style(color::GREY_3)) + .push( + button::secondary(None, "Select") + .width(Length::Units(200)) + .on_press(Message::CreateWallet), + ) + .align_items(Alignment::Center), ) - .style(theme::Button::Secondary) - .on_press(Message::CreateWallet), + .padding(20), ) .push( - Button::new( - Container::new( - Column::new() - .width(Length::Units(250)) - .push(icon::people_icon().size(50).width(Length::Units(100))) - .push(text("Participate in a new wallet")) - .align_items(Alignment::Center), - ) - .padding(20), + Container::new( + Column::new() + .spacing(20) + .align_items(Alignment::Center) + .push( + image::participate_in_new_wallet_icon() + .width(Length::Units(200)), + ) + .push(p1_regular("Participate in new wallet").style(color::GREY_3)) + .push( + button::secondary(None, "Select") + .width(Length::Units(200)) + .on_press(Message::ParticipateWallet), + ) + .align_items(Alignment::Center), ) - .style(theme::Button::Secondary) - .on_press(Message::ParticipateWallet), + .padding(20), ) .push( - Button::new( - Container::new( - Column::new() - .width(Length::Units(250)) - .push(icon::import_icon().size(50).width(Length::Units(100))) - .push(text("Import a wallet backup")) - .align_items(Alignment::Center), - ) - .padding(20), + Container::new( + Column::new() + .spacing(20) + .align_items(Alignment::Center) + .push(image::restore_wallet_icon().width(Length::Units(100))) + .push(p1_regular("Restore a wallet").style(color::GREY_3)) + .push( + button::secondary(None, "Select") + .width(Length::Units(200)) + .on_press(Message::ImportWallet), + ) + .align_items(Alignment::Center), ) - .style(theme::Button::Secondary) - .on_press(Message::ImportWallet), + .padding(20), ), ) .width(Length::Fill) diff --git a/gui/ui/src/icon.rs b/gui/ui/src/icon.rs index 756de529..9ce74dab 100644 --- a/gui/ui/src/icon.rs +++ b/gui/ui/src/icon.rs @@ -110,10 +110,6 @@ pub fn up_icon() -> Text<'static> { bootstrap_icon('\u{F27C}') } -pub fn people_icon() -> Text<'static> { - bootstrap_icon('\u{F4CF}') -} - pub fn network_icon() -> Text<'static> { bootstrap_icon('\u{F40D}') } diff --git a/gui/ui/src/image.rs b/gui/ui/src/image.rs index 55783f6a..ec1ca8ae 100644 --- a/gui/ui/src/image.rs +++ b/gui/ui/src/image.rs @@ -12,3 +12,24 @@ pub fn liana_grey_logo() -> Svg { let h = Handle::from_memory(LIANA_LOGO_GREY.to_vec()); Svg::new(h) } + +const CREATE_NEW_WALLET_ICON: &[u8] = include_bytes!("../static/icons/blueprint.svg"); + +pub fn create_new_wallet_icon() -> Svg { + let h = Handle::from_memory(CREATE_NEW_WALLET_ICON.to_vec()); + Svg::new(h) +} + +const PARTICIPATE_IN_NEW_WALLET_ICON: &[u8] = include_bytes!("../static/icons/discussion.svg"); + +pub fn participate_in_new_wallet_icon() -> Svg { + let h = Handle::from_memory(PARTICIPATE_IN_NEW_WALLET_ICON.to_vec()); + Svg::new(h) +} + +const RESTORE_WALLET_ICON: &[u8] = include_bytes!("../static/icons/syncdata.svg"); + +pub fn restore_wallet_icon() -> Svg { + let h = Handle::from_memory(RESTORE_WALLET_ICON.to_vec()); + Svg::new(h) +} diff --git a/gui/ui/static/icons/blueprint.svg b/gui/ui/static/icons/blueprint.svg new file mode 100644 index 00000000..8977d1fb --- /dev/null +++ b/gui/ui/static/icons/blueprint.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/gui/ui/static/icons/discussion.svg b/gui/ui/static/icons/discussion.svg new file mode 100644 index 00000000..937006a9 --- /dev/null +++ b/gui/ui/static/icons/discussion.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/ui/static/icons/syncdata.svg b/gui/ui/static/icons/syncdata.svg new file mode 100644 index 00000000..f483f3c1 --- /dev/null +++ b/gui/ui/static/icons/syncdata.svg @@ -0,0 +1,5 @@ + + + + + From 4c08f4ae350f423896e9e6b8fe9ef0aa8ae66bde Mon Sep 17 00:00:00 2001 From: edouard Date: Tue, 9 May 2023 21:29:09 +0200 Subject: [PATCH 5/7] Add grey brand logo to installer and launcher --- gui/src/installer/view.rs | 143 +++++++++++++++++++++----------------- gui/src/launcher.rs | 119 ++++++++++++++++--------------- gui/ui/src/image.rs | 6 ++ 3 files changed, 149 insertions(+), 119 deletions(-) diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index 71862925..7a92976f 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -76,73 +76,92 @@ const NETWORKS: [Network; 4] = [ ]; pub fn welcome<'a>() -> Element<'a, Message> { - Container::new(Container::new( + Container::new( Column::new() + .push(Container::new(image::liana_brand_grey().width(Length::Units(200))).padding(100)) .push( - Row::new() - .align_items(Alignment::End) - .spacing(20) - .push( - Container::new( - Column::new() + Container::new( + Column::new() + .push( + Row::new() + .align_items(Alignment::End) .spacing(20) - .align_items(Alignment::Center) - .push(image::create_new_wallet_icon().width(Length::Units(100))) - .push(p1_regular("Create a new wallet").style(color::GREY_3)) .push( - button::secondary(None, "Select") - .width(Length::Units(200)) - .on_press(Message::CreateWallet), + Container::new( + Column::new() + .spacing(20) + .align_items(Alignment::Center) + .push( + image::create_new_wallet_icon() + .width(Length::Units(100)), + ) + .push( + p1_regular("Create a new wallet") + .style(color::GREY_3), + ) + .push( + button::secondary(None, "Select") + .width(Length::Units(200)) + .on_press(Message::CreateWallet), + ) + .align_items(Alignment::Center), + ) + .padding(20), ) - .align_items(Alignment::Center), + .push( + Container::new( + Column::new() + .spacing(20) + .align_items(Alignment::Center) + .push( + image::participate_in_new_wallet_icon() + .width(Length::Units(200)), + ) + .push( + p1_regular("Participate in new wallet") + .style(color::GREY_3), + ) + .push( + button::secondary(None, "Select") + .width(Length::Units(200)) + .on_press(Message::ParticipateWallet), + ) + .align_items(Alignment::Center), + ) + .padding(20), + ) + .push( + Container::new( + Column::new() + .spacing(20) + .align_items(Alignment::Center) + .push( + image::restore_wallet_icon() + .width(Length::Units(100)), + ) + .push( + p1_regular("Restore a wallet").style(color::GREY_3), + ) + .push( + button::secondary(None, "Select") + .width(Length::Units(200)) + .on_press(Message::ImportWallet), + ) + .align_items(Alignment::Center), + ) + .padding(20), + ), ) - .padding(20), - ) - .push( - Container::new( - Column::new() - .spacing(20) - .align_items(Alignment::Center) - .push( - image::participate_in_new_wallet_icon() - .width(Length::Units(200)), - ) - .push(p1_regular("Participate in new wallet").style(color::GREY_3)) - .push( - button::secondary(None, "Select") - .width(Length::Units(200)) - .on_press(Message::ParticipateWallet), - ) - .align_items(Alignment::Center), - ) - .padding(20), - ) - .push( - Container::new( - Column::new() - .spacing(20) - .align_items(Alignment::Center) - .push(image::restore_wallet_icon().width(Length::Units(100))) - .push(p1_regular("Restore a wallet").style(color::GREY_3)) - .push( - button::secondary(None, "Select") - .width(Length::Units(200)) - .on_press(Message::ImportWallet), - ) - .align_items(Alignment::Center), - ) - .padding(20), - ), - ) - .width(Length::Fill) - .height(Length::Fill) - .spacing(50) - .align_items(Alignment::Center), - )) - .center_y() - .center_x() - .height(Length::Fill) - .width(Length::Fill) + .push(Space::with_height(Length::Units(100))) + .spacing(50) + .align_items(Alignment::Center), + ) + .center_y() + .center_x() + .width(Length::Fill) + .height(Length::Fill), + ), + ) .into() } @@ -274,8 +293,6 @@ pub fn define_descriptor<'a>( ) .push_maybe(error.map(|e| card::error("Failed to create descriptor", e.to_string()))) .push(Space::with_height(Length::Units(20))) - .width(Length::Fill) - .height(Length::Fill) .spacing(50), false, ) diff --git a/gui/src/launcher.rs b/gui/src/launcher.rs index 94a6ab26..c8b0b8df 100644 --- a/gui/src/launcher.rs +++ b/gui/src/launcher.rs @@ -1,11 +1,11 @@ use std::path::PathBuf; -use iced::{Alignment, Command, Length, Subscription}; +use iced::{widget::Space, Alignment, Command, Length, Subscription}; use liana::{config::ConfigError, miniscript::bitcoin::Network}; use liana_ui::{ component::{badge, card, text::*}, - icon, theme, + icon, image, theme, util::*, widget::*, }; @@ -76,69 +76,76 @@ impl Launcher { pub fn view(&self) -> Element { Into::>::into( - Container::new( - Column::new() - .spacing(30) - .push(text("Welcome back").size(50).bold()) - .push_maybe(self.error.as_ref().map(|e| card::simple(text(e)))) - .push( - self.choices - .iter() - .fold( - Column::new() - .push(text("Select network:").small().bold()) - .spacing(10), - |col, choice| { - col.push( + Column::new() + .push( + Container::new(image::liana_brand_grey().width(Length::Units(200))) + .padding(100), + ) + .push( + Container::new( + Column::new() + .spacing(30) + .push(text("Welcome back").size(50).bold()) + .push_maybe(self.error.as_ref().map(|e| card::simple(text(e)))) + .push( + self.choices + .iter() + .fold( + Column::new() + .push(text("Select network:").small().bold()) + .spacing(10), + |col, choice| { + col.push( + Button::new( + Row::new() + .spacing(20) + .align_items(Alignment::Center) + .push( + badge::Badge::new(icon::bitcoin_icon()) + .style(match choice { + Network::Bitcoin => { + theme::Badge::Bitcoin + } + _ => theme::Badge::Standard, + }), + ) + .push(text(match choice { + Network::Bitcoin => "Bitcoin Mainnet", + Network::Testnet => "Bitcoin Testnet", + Network::Signet => "Bitcoin Signet", + Network::Regtest => "Bitcoin Regtest", + })), + ) + .on_press(ViewMessage::Check(*choice)) + .padding(10) + .width(Length::Fill) + .style(theme::Button::Border), + ) + }, + ) + .push( Button::new( Row::new() .spacing(20) .align_items(Alignment::Center) - .push( - badge::Badge::new(icon::bitcoin_icon()).style( - match choice { - Network::Bitcoin => { - theme::Badge::Bitcoin - } - _ => theme::Badge::Standard, - }, - ), - ) - .push(text(match choice { - Network::Bitcoin => "Bitcoin Mainnet", - Network::Testnet => "Bitcoin Testnet", - Network::Signet => "Bitcoin Signet", - Network::Regtest => "Bitcoin Regtest", - })), + .push(badge::Badge::new(icon::plus_icon())) + .push(text("Install Liana on another network")), ) - .on_press(ViewMessage::Check(*choice)) + .on_press(ViewMessage::StartInstall) .padding(10) .width(Length::Fill) - .style(theme::Button::Border), - ) - }, + .style(theme::Button::TransparentBorder), + ), ) - .push( - Button::new( - Row::new() - .spacing(20) - .align_items(Alignment::Center) - .push(badge::Badge::new(icon::plus_icon())) - .push(text("Install Liana on another network")), - ) - .on_press(ViewMessage::StartInstall) - .padding(10) - .width(Length::Fill) - .style(theme::Button::TransparentBorder), - ), + .max_width(500) + .align_items(Alignment::Center), ) - .max_width(500) - .align_items(Alignment::Center), - ) - .width(Length::Fill) - .height(Length::Fill) - .center_x() - .center_y(), + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y(), + ) + .push(Space::with_height(Length::Units(100))), ) .map(Message::View) } diff --git a/gui/ui/src/image.rs b/gui/ui/src/image.rs index ec1ca8ae..635466b0 100644 --- a/gui/ui/src/image.rs +++ b/gui/ui/src/image.rs @@ -3,6 +3,7 @@ use iced::{widget::svg::Handle, window::icon}; const LIANA_APP_ICON: &[u8] = include_bytes!("../static/logos/liana-app-icon.png"); const LIANA_LOGO_GREY: &[u8] = include_bytes!("../static/logos/LIANA_SYMBOL_Gray.svg"); +const LIANA_BRAND_GREY: &[u8] = include_bytes!("../static/logos/LIANA_BRAND_Gray.svg"); pub fn liana_app_icon() -> icon::Icon { icon::Icon::from_file_data(LIANA_APP_ICON, None).unwrap() @@ -13,6 +14,11 @@ pub fn liana_grey_logo() -> Svg { Svg::new(h) } +pub fn liana_brand_grey() -> Svg { + let h = Handle::from_memory(LIANA_BRAND_GREY.to_vec()); + Svg::new(h) +} + const CREATE_NEW_WALLET_ICON: &[u8] = include_bytes!("../static/icons/blueprint.svg"); pub fn create_new_wallet_icon() -> Svg { From b9ca312b073968f3108d6082e06705eda8441d8d Mon Sep 17 00:00:00 2001 From: edouard Date: Wed, 10 May 2023 09:51:07 +0200 Subject: [PATCH 6/7] ui: add success mark and key mark --- gui/src/installer/view.rs | 42 +++++++++------------------- gui/ui/src/component/hw.rs | 12 ++++---- gui/ui/src/image.rs | 14 ++++++++++ gui/ui/static/icons/key-mark.svg | 7 +++++ gui/ui/static/icons/success-mark.svg | 4 +++ 5 files changed, 44 insertions(+), 35 deletions(-) create mode 100644 gui/ui/static/icons/key-mark.svg create mode 100644 gui/ui/static/icons/success-mark.svg diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index 7a92976f..f504c4f8 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -1120,12 +1120,7 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> { Column::new() .spacing(15) .align_items(Alignment::Center) - .push( - icon::key_icon() - .size(30) - .width(Length::Units(50)) - .style(color::GREY_3), - ), + .push(image::key_mark_icon().width(Length::Units(30))), ) .height(Length::Fill) .align_y(alignment::Vertical::Center), @@ -1162,30 +1157,19 @@ pub fn defined_descriptor_key( ), ) .push( - Column::new() - .align_items(Alignment::Center) - .spacing(5) - .push( - Container::new( - Column::new() - .spacing(5) - .align_items(Alignment::Center) - .push( - scrollable(text(name).bold()).horizontal_scroll( - Properties::new().width(2).scroller_width(2), - ), - ) - .push( - icon::circle_check_icon() - .style(color::GREEN) - .size(20) - .width(Length::Units(50)), - ), + Container::new( + Column::new() + .spacing(10) + .align_items(Alignment::Center) + .push( + scrollable(text(name).bold()) + .horizontal_scroll(Properties::new().width(2).scroller_width(2)), ) - .height(Length::Fill) - .align_y(alignment::Vertical::Center), - ) - .height(Length::Fill), + .push(image::success_mark_icon().width(Length::Units(50))) + .push(Space::with_width(Length::Units(1))), + ) + .height(Length::Fill) + .align_y(alignment::Vertical::Center), ) .push( button::secondary(Some(icon::pencil_icon()), "Edit").on_press(message::DefineKey::Edit), diff --git a/gui/ui/src/component/hw.rs b/gui/ui/src/component/hw.rs index 67acd4f4..b5f00c3c 100644 --- a/gui/ui/src/component/hw.rs +++ b/gui/ui/src/component/hw.rs @@ -1,4 +1,4 @@ -use crate::{color, component::text, icon, theme, util::*, widget::*}; +use crate::{color, component::text, icon, image, theme, util::*, widget::*}; use iced::{ widget::{column, container, row, tooltip}, Alignment, Length, @@ -121,7 +121,7 @@ pub fn selected_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>( ]) .width(Length::Fill) .into(), - icon::circle_check_icon().style(color::GREEN).into(), + image::success_mark_icon().width(Length::Units(50)).into(), ]) .align_items(Alignment::Center), ) @@ -151,8 +151,8 @@ pub fn sign_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Displa .width(Length::Fill) .into(), row(vec![ - icon::circle_check_icon().style(color::GREEN).into(), text::p1_regular("Signed").style(color::GREEN).into(), + image::success_mark_icon().width(Length::Units(50)).into(), ]) .align_items(Alignment::Center) .spacing(5) @@ -186,8 +186,8 @@ pub fn registration_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F .width(Length::Fill) .into(), row(vec![ - icon::circle_check_icon().style(color::GREEN).into(), text::p1_regular("Registered").style(color::GREEN).into(), + image::success_mark_icon().width(Length::Units(50)).into(), ]) .align_items(Alignment::Center) .spacing(5) @@ -250,8 +250,8 @@ pub fn sign_success_hot_signer<'a, T: 'a, F: Display>( .width(Length::Fill) .into(), row(vec![ - icon::circle_check_icon().style(color::GREEN).into(), text::p1_regular("Signed").style(color::GREEN).into(), + image::success_mark_icon().width(Length::Units(50)).into(), ]) .align_items(Alignment::Center) .spacing(5) @@ -284,7 +284,7 @@ pub fn selected_hot_signer<'a, T: 'a, F: Display>( ]) .width(Length::Fill) .into(), - icon::circle_check_icon().style(color::GREEN).into(), + image::success_mark_icon().width(Length::Units(50)).into(), ]) .align_items(Alignment::Center), ) diff --git a/gui/ui/src/image.rs b/gui/ui/src/image.rs index 635466b0..0d095bb6 100644 --- a/gui/ui/src/image.rs +++ b/gui/ui/src/image.rs @@ -39,3 +39,17 @@ pub fn restore_wallet_icon() -> Svg { let h = Handle::from_memory(RESTORE_WALLET_ICON.to_vec()); Svg::new(h) } + +const SUCCESS_MARK_ICON: &[u8] = include_bytes!("../static/icons/success-mark.svg"); + +pub fn success_mark_icon() -> Svg { + let h = Handle::from_memory(SUCCESS_MARK_ICON.to_vec()); + Svg::new(h) +} + +const KEY_MARK_ICON: &[u8] = include_bytes!("../static/icons/key-mark.svg"); + +pub fn key_mark_icon() -> Svg { + let h = Handle::from_memory(KEY_MARK_ICON.to_vec()); + Svg::new(h) +} diff --git a/gui/ui/static/icons/key-mark.svg b/gui/ui/static/icons/key-mark.svg new file mode 100644 index 00000000..22937e54 --- /dev/null +++ b/gui/ui/static/icons/key-mark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/gui/ui/static/icons/success-mark.svg b/gui/ui/static/icons/success-mark.svg new file mode 100644 index 00000000..66548919 --- /dev/null +++ b/gui/ui/static/icons/success-mark.svg @@ -0,0 +1,4 @@ + + + + From 54e9446bc0e08e851213f844da51dd312c6aefde Mon Sep 17 00:00:00 2001 From: edouard Date: Wed, 10 May 2023 09:59:03 +0200 Subject: [PATCH 7/7] fix: add cycle badge to send-to-self psbts --- gui/src/app/view/psbts.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gui/src/app/view/psbts.rs b/gui/src/app/view/psbts.rs index 2469b6d1..ed77e761 100644 --- a/gui/src/app/view/psbts.rs +++ b/gui/src/app/view/psbts.rs @@ -96,7 +96,11 @@ fn spend_tx_list_view<'a>(i: usize, tx: &SpendTx) -> Element<'a, Message> { Row::new() .push( Row::new() - .push(badge::spend()) + .push(if tx.is_self_send() { + badge::cycle() + } else { + badge::spend() + }) .push(if !tx.sigs.recovery_paths().is_empty() { badge::recovery() } else {