use ratatui::layout::Position;
use rtlibs_utils::time::date;
use time::Date;
use time::Month;
use crate::widgets::InputNumberState;
#[derive(Debug)]
pub(crate) enum InputDateFocus
{
Day,
Month,
Year,
}
#[derive(Debug)]
pub struct InputDateState
{
pub(crate) label: Option<String>,
pub(crate) input_mode: InputDateFocus,
pub(crate) input_day: InputNumberState,
pub(crate) input_month: InputNumberState,
pub(crate) input_year: InputNumberState,
pub(crate) min_value: Option<Date>,
pub(crate) max_value: Option<Date>,
}
impl std::default::Default for InputDateState
{
fn default() -> Self
{
Self::new()
}
}
impl InputDateState
{
pub fn new() -> Self
{
Self {
label: None,
input_mode: InputDateFocus::Day,
input_day: InputNumberState::new()
.with_max_length(2)
.min(1)
.max(31),
input_month: InputNumberState::new()
.with_max_length(2)
.min(1)
.max(12),
input_year: InputNumberState::new()
.with_max_length(4)
.min(1900)
.max(2500),
min_value: None,
max_value: None,
}
}
pub fn input(&self) -> Option<Date>
{
let day: u8 = match self
.input_day
.input()
.filter(|i| *i != 0)
.and_then(
|i| {
i.try_into()
.ok()
},
)
{
Some(value) => value,
None => return None,
};
let month: u8 = match self
.input_month
.input()
.filter(|i| *i >= 1 && *i <= 12)
.and_then(
|i| {
i.try_into()
.ok()
},
)
{
Some(value) => value,
None => return None,
};
let month = Month::January.nth_next(month - 1);
let year: i32 = match self
.input_year
.input()
.and_then(
|i| {
i.try_into()
.ok()
},
)
{
Some(value) => value,
None => return None,
};
let date = match Date::from_calendar_date(
year, month, day,
)
{
Ok(value) => value,
Err(_) => return None,
};
if let Some(min) = self.min_value
{
if date < min
{
return None;
}
}
if let Some(max) = self.max_value
{
if date > max
{
return None;
}
}
Some(date)
}
pub fn set_label<S>(
&mut self,
label: S,
) where
S: AsRef<str>,
{
self.label = Some(
label
.as_ref()
.to_string(),
);
}
pub fn remove_label(&mut self)
{
self.label
.take();
}
pub fn with_label<S>(
mut self,
label: S,
) -> Self
where
S: AsRef<str>,
{
self.set_label(label);
self
}
pub fn max(
mut self,
value: Date,
) -> Self
{
self.max_value = Some(value);
self
}
pub fn min(
mut self,
value: Date,
) -> Self
{
self.min_value = Some(value);
self
}
pub fn set(
&mut self,
value: Date,
)
{
let (day, month, year) = date::to_dmy(value);
self.input_day
.set_str(format!("{day:02}"));
self.input_month
.set_str(format!("{month:02}"));
self.input_year
.set_str(format!("{year:04}"));
self.input_mode = InputDateFocus::Day;
}
pub fn reset_cursor(&mut self)
{
self.input_day
.reset_cursor();
self.input_month
.reset_cursor();
self.input_year
.reset_cursor();
}
pub fn with_default(
mut self,
value: Date,
) -> Self
{
self.set(value);
self
}
pub fn cursor(&self) -> Position
{
match self.input_mode
{
InputDateFocus::Day => self
.input_day
.cursor(),
InputDateFocus::Month => self
.input_month
.cursor(),
InputDateFocus::Year => self
.input_year
.cursor(),
}
}
pub fn clear(&mut self)
{
self.input_day
.clear();
self.input_month
.clear();
self.input_year
.clear();
}
}