use rust_on_rails::prelude::*;
use crate::elements::images::Icon;
use crate::elements::text::{Text, TextStyle};
use crate::layout::{Column, Offset, Padding, Row, Size, Stack};
use crate::PelicanUI;
#[derive(Debug, Component)]
pub struct AmountDisplay(Column, Text, SubText);
impl OnEvent for AmountDisplay {}
impl AmountDisplay {
pub fn new(ctx: &mut Context) -> Self {
let font_size = ctx.get::<PelicanUI>().theme.fonts.size.title;
AmountDisplay (
Column::new(16.0, Offset::Center, Size::Fit, Padding(16.0, 64.0, 16.0, 64.0)),
Text::new(ctx, "$0.00", TextStyle::Heading, font_size, Align::Left),
SubText::new(ctx, "0.00000000 BTC")
)
}
pub fn usd(&mut self) -> &mut String {&mut self.1.text().spans[0].text}
pub fn btc(&mut self) -> &mut String {&mut self.2.2.text().spans[0].text}
}
#[derive(Debug, Component)]
struct SubText(Row, Option<Image>, Text, #[skip] bool);
impl OnEvent for SubText {}
impl SubText {
fn new(ctx: &mut Context, btc: &'static str) -> Self {
let text_size = ctx.get::<PelicanUI>().theme.fonts.size.lg;
SubText(Row::center(8.0), None, Text::new(ctx, btc, TextStyle::Secondary, text_size, Align::Left), true)
}
fn set_error(&mut self, ctx: &mut Context, err: &'static str) {
let theme = &ctx.get::<PelicanUI>().theme;
let (color, text_size) = (theme.colors.status.danger, theme.fonts.size.lg);
self.1 = Some(Icon::new(ctx, "error", color, 24.0));
self.2 = Text::new(ctx, err, TextStyle::Error, text_size, Align::Left);
}
fn set_subtext(&mut self, ctx: &mut Context, txt: &'static str) {
let text_size = ctx.get::<PelicanUI>().theme.fonts.size.lg;
self.1 = None;
self.2 = Text::new(ctx, txt, TextStyle::Secondary, text_size, Align::Left);
}
fn error(&mut self) -> &mut bool {&mut self.3}
fn _text(&mut self) -> &mut String {&mut self.2.text().spans[0].text}
}
#[derive(Debug, Component)]
pub struct AmountInput(Stack, AmountInputContent);
impl OnEvent for AmountInput {}
impl AmountInput {
pub fn new(ctx: &mut Context) -> Self {
AmountInput (
Stack(Offset::Center, Offset::Center, Size::Fit, Size::fill(), Padding::default()),
AmountInputContent::new(ctx),
)
}
pub fn usd(&mut self) -> String {self.1.1.value()}
pub fn btc(&mut self) -> &mut f32 { &mut self.1.5 }
pub fn error(&mut self) -> &mut bool {self.1.2.error()}
pub fn set_min(&mut self, a: f32) {self.1.3.0 = a;}
pub fn set_max(&mut self, a: f32) {self.1.3.1 = a;}
pub fn set_price(&mut self, a: f32) {self.1.4 = a;}
}
#[derive(Debug, Component)]
pub struct AmountInputContent(Column, Display, SubText, #[skip] (f32, f32), #[skip] f32, #[skip] f32);
impl AmountInputContent {
pub fn new(ctx: &mut Context) -> Self {
let subtext = if !crate::config::IS_MOBILE {"Type dollar amount."} else {"0.00001234 BTC"};
AmountInputContent (
Column::new(16.0, Offset::Center, Size::Fit, Padding(16.0, 64.0, 16.0, 64.0)),
Display::new(ctx),
SubText::new(ctx, subtext),
(0.0, 0.0), 0.0, 0.0
)
}
}
impl OnEvent for AmountInputContent {
fn on_event(&mut self, ctx: &mut Context, event: &mut dyn Event) -> bool {
if let Some(KeyboardEvent{state: KeyboardState::Pressed, key}) = event.downcast_ref() {
let font_size = ctx.get::<PelicanUI>().theme.fonts.size;
let mut t = self.1.amount().text.replace(",", "");
let mut digit_count = t.chars().filter(|ch| ch.is_ascii_digit()).count();
match key {
Key::Named(NamedKey::Delete | NamedKey::Backspace) if !t.is_empty() => match t.as_str() {
"$0" => {},
_ if t.len() == 1 => t = "0".to_string(),
_ => { t.pop(); }
},
Key::Character(c) => {
if digit_count < 8 {
let character = c.chars().next().unwrap();
if character.is_ascii_digit() {
match t.find('.') {
Some(i) if t[i + 1..].len() < 2 => t.push(character),
None => match t.as_str() {
"0" => t = character.to_string(),
_ => t.push(character),
},
_ => {}
}
} else if character == '.' && !t.contains('.') && digit_count + 2 <= 8 {
t.push('.');
}
}
}
_ => {return true}
}
self.1.zeros().text = match t.find('.') {
Some(i) => match t[i + 1..].len() {
0 => "00",
1 => "0",
_ => "",
},
None => "",
}.to_string();
digit_count = t.chars().filter(|ch| ch.is_ascii_digit()).count();
let (dollars, cents) = match t.find('.') {
Some(i) => (&t[..i], Some(&t[i..])),
None => (t.as_str(), None),
};
let formatted_dollars: String = dollars
.chars().rev().enumerate()
.map(|(i, ch)| if i > 0 && i % 3 == 0 { vec![',', ch] } else { vec![ch] })
.flatten().collect::<Vec<_>>().into_iter()
.rev().collect();
let t_formatted = format!("{}{}", formatted_dollars, cents.unwrap_or(""));
let total_digits = digit_count + self.1.zeros().text.len();
let size = if total_digits <= 5 { font_size.title } else { font_size.h1 };
self.1.amount().text = t_formatted.clone();
self.1.amount().font_size = size;
self.1.amount().line_height = size * 1.25;
self.1.zeros().font_size = size;
self.1.zeros().line_height = size * 1.25;
self.1.currency().font_size = size;
self.1.currency().line_height = size * 1.25;
let value = t_formatted.replace(",", "").parse::<f32>().unwrap_or(0.0);
println!("VAL: {:?}", value);
match t_formatted.as_str() {
"0" | "0." | "0.0" | "0.00" if !crate::config::IS_MOBILE => {
self.2.set_subtext(ctx, "Type dollar amount."); self.2.3 = true; }
_ if value < self.3.0 => {
let error = format!("${:.2} minimum.", self.3.0);
self.2.set_error(ctx, Box::leak(error.into_boxed_str())); self.2.3 = true; }
_ if value > self.3.1 => {
let error = format!("${:.2} maximum.", self.3.1);
self.2.set_error(ctx, Box::leak(error.into_boxed_str())); self.2.3 = true; }
_ => {
self.5 = value*self.4;
let amount = format!("{:.8} BTC", self.5);
self.2.set_subtext(ctx, Box::leak(amount.into_boxed_str()));
self.2.3 = false; }
}
}
true
}
}
#[derive(Debug, Component)]
struct Display(Row, Text, Text, Text);
impl OnEvent for Display {}
impl Display {
pub fn new(ctx: &mut Context) -> Self {
let theme = &ctx.get::<PelicanUI>().theme;
let font_size = theme.fonts.size.title;
let (mc, dc) = (theme.colors.text.heading, theme.colors.text.secondary);
Display (
Row::center(0.0),
Text::new(ctx, "$", TextStyle::Label(mc), font_size, Align::Left),
Text::new(ctx, "0", TextStyle::Label(mc), font_size, Align::Left),
Text::new(ctx, "", TextStyle::Label(dc), font_size, Align::Left),
)
}
pub fn value(&mut self) -> String {self.amount().text.clone()+"."+&self.zeros().text}
pub fn amount(&mut self) -> &mut Span {&mut self.2.text().spans[0]}
pub fn zeros(&mut self) -> &mut Span {&mut self.3.text().spans[0]}
pub fn currency(&mut self) -> &mut Span {&mut self.1.text().spans[0]}
}