From d95660460ff4e573513fcbb2dd20700627b5d86f Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Mon, 27 May 2024 10:45:59 -0500 Subject: [PATCH] prettify transaction list a bit --- assets/icons/bolt.svg | 3 ++ assets/icons/chain.svg | 3 ++ src/components/colors.rs | 4 +++ src/components/icon.rs | 11 +++---- src/components/mod.rs | 3 ++ src/components/screen_header.rs | 6 ++-- src/components/transaction_item.rs | 47 +++++++++++++++++++++++------- src/components/util.rs | 25 ++++++++++++++++ src/routes/history.rs | 7 +++-- src/routes/home.rs | 5 ++-- 10 files changed, 92 insertions(+), 22 deletions(-) create mode 100644 assets/icons/bolt.svg create mode 100644 assets/icons/chain.svg create mode 100644 src/components/colors.rs diff --git a/assets/icons/bolt.svg b/assets/icons/bolt.svg new file mode 100644 index 0000000..65c9e1a --- /dev/null +++ b/assets/icons/bolt.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/chain.svg b/assets/icons/chain.svg new file mode 100644 index 0000000..9de731f --- /dev/null +++ b/assets/icons/chain.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/colors.rs b/src/components/colors.rs new file mode 100644 index 0000000..0b9639c --- /dev/null +++ b/src/components/colors.rs @@ -0,0 +1,4 @@ +use iced::Color; + +pub const MUTINY_GREEN: Color = Color::from_rgb(40. / 255., 164. / 255., 127. / 255.); +pub const MUTINY_RED: Color = Color::from_rgb(250. / 255., 0., 80. / 255.); diff --git a/src/components/icon.rs b/src/components/icon.rs index 39794a4..fe1c9ea 100644 --- a/src/components/icon.rs +++ b/src/components/icon.rs @@ -1,6 +1,4 @@ -use iced::{widget::Svg, Element, Theme}; - -use crate::Message; +use iced::{widget::Svg, Theme}; pub enum SvgIcon { ChevronDown, @@ -17,9 +15,11 @@ pub enum SvgIcon { Qr, Restart, SmallClose, + Bolt, + Chain, } -pub fn map_icon<'a>(icon: SvgIcon, width: f32, height: f32) -> Element<'a, Message, Theme> { +pub fn map_icon<'a>(icon: SvgIcon, width: f32, height: f32) -> Svg<'a, Theme> { match icon { SvgIcon::ChevronDown => Svg::from_path("assets/icons/chevron_down.svg"), SvgIcon::DownLeft => Svg::from_path("assets/icons/down_left.svg"), @@ -35,8 +35,9 @@ pub fn map_icon<'a>(icon: SvgIcon, width: f32, height: f32) -> Element<'a, Messa SvgIcon::Qr => Svg::from_path("assets/icons/qr.svg"), SvgIcon::Restart => Svg::from_path("assets/icons/restart.svg"), SvgIcon::SmallClose => Svg::from_path("assets/icons/small_close.svg"), + SvgIcon::Bolt => Svg::from_path("assets/icons/bolt.svg"), + SvgIcon::Chain => Svg::from_path("assets/icons/chain.svg"), } .width(width) .height(height) - .into() } diff --git a/src/components/mod.rs b/src/components/mod.rs index 0c2221b..e747508 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -45,3 +45,6 @@ pub use mini_copy::*; mod toast; pub use toast::*; + +mod colors; +pub use colors::*; diff --git a/src/components/screen_header.rs b/src/components/screen_header.rs index 7290b7a..94c5a04 100644 --- a/src/components/screen_header.rs +++ b/src/components/screen_header.rs @@ -5,7 +5,7 @@ use iced::{ use crate::{HarborWallet, Message}; -use super::{hr, map_icon, vr, FederationItem, SvgIcon}; +use super::{format_amount, hr, map_icon, vr, FederationItem, SvgIcon}; pub fn h_screen_header(harbor: &HarborWallet, show_balance: bool) -> Element { if let Some(item) = harbor.federation_list.first() { @@ -17,7 +17,9 @@ pub fn h_screen_header(harbor: &HarborWallet, show_balance: bool) -> Element Element { direction, timestamp, } = item; - let row = row![ - text(format!("{kind:?}")).size(24), - text(format!("{amount} sats")).size(24), - text(format!("{direction:?}")).size(24), - text(format!("{timestamp}")).size(24), - ] - .spacing(16); + let kind_icon = match kind { + TransactionItemKind::Lightning => map_icon(super::SvgIcon::Bolt, 24., 24.), + TransactionItemKind::Onchain => map_icon(super::SvgIcon::Chain, 24., 24.), + }; + + let direction_icon = match direction { + TransactionDirection::Incoming => { + map_icon(super::SvgIcon::DownLeft, 24., 24.).style(|_theme, _status| svg::Style { + color: Some(MUTINY_GREEN), + }) + } + TransactionDirection::Outgoing => { + map_icon(super::SvgIcon::UpRight, 24., 24.).style(|_theme, _status| svg::Style { + color: Some(MUTINY_RED), + }) + } + }; + + let formatted_amount = text(format_amount(*amount)).size(24); + + let row = row![direction_icon, kind_icon, formatted_amount,] + .align_items(iced::Alignment::Center) + .spacing(16); + + let timestamp = text(format_timestamp(timestamp)) + .size(18) + .style(|theme: &Theme| { + let gray = lighten(theme.palette().background, 0.5); + Style { color: Some(gray) } + }); + + let col = column![row, timestamp].spacing(8); - row.into() + col.into() } diff --git a/src/components/util.rs b/src/components/util.rs index 437c7a6..d7a9e70 100644 --- a/src/components/util.rs +++ b/src/components/util.rs @@ -32,3 +32,28 @@ fn to_hsl(color: Color) -> Hsl { fn from_hsl(hsl: Hsl) -> Color { Rgb::from_color(hsl).into() } + +pub fn format_timestamp(timestamp: &u64) -> String { + let signed = timestamp.to_owned() as i64; + let date_time = chrono::DateTime::from_timestamp(signed, 0).unwrap(); + format!("{}", date_time.format("%m/%d/%Y, %l:%M %P")) +} + +pub fn format_amount(amount: u64) -> String { + if amount == 1 { + return "1 sat".to_string(); + } + // https://stackoverflow.com/questions/26998485/is-it-possible-to-print-a-number-formatted-with-thousand-separator-in-rust + // Rust is a real baby about doing useful things + let num = amount + .to_string() + .as_bytes() + .rchunks(3) + .rev() + .map(std::str::from_utf8) + .collect::, _>>() + .unwrap() + .join(","); + + format!("{num} sats") +} diff --git a/src/routes/history.rs b/src/routes/history.rs index 3e3d155..9ef1509 100644 --- a/src/routes/history.rs +++ b/src/routes/history.rs @@ -1,7 +1,7 @@ use iced::widget::column; use iced::Element; -use crate::components::{basic_layout, h_header, h_screen_header, h_transaction_item}; +use crate::components::{basic_layout, h_header, h_screen_header, h_transaction_item, hr}; use crate::{HarborWallet, Message}; pub fn history(harbor: &HarborWallet) -> Element { @@ -11,8 +11,9 @@ pub fn history(harbor: &HarborWallet) -> Element { .transaction_history .iter() .fold(column![], |column, item| { - column.push(h_transaction_item(item)) - }); + column.push(h_transaction_item(item)).push(hr()) + }) + .spacing(16); let column = column![header, transactions].spacing(48); diff --git a/src/routes/home.rs b/src/routes/home.rs index 8913d74..51d7717 100644 --- a/src/routes/home.rs +++ b/src/routes/home.rs @@ -1,4 +1,4 @@ -use crate::components::{h_button, h_screen_header, SvgIcon}; +use crate::components::{format_amount, h_button, h_screen_header, SvgIcon}; use iced::widget::{center, column, container, row, text}; use iced::{Alignment, Element, Length}; @@ -7,7 +7,8 @@ use crate::{HarborWallet, Message}; use super::Route; pub fn home(harbor: &HarborWallet) -> Element { - let balance = text(format!("{} sats", harbor.balance_sats)).size(64); + let formatted_balance = format_amount(harbor.balance_sats); + let balance = text(formatted_balance).size(64); let send_button = h_button("Send", SvgIcon::UpRight, false).on_press(Message::Navigate(Route::Send)); let receive_button =