use chrono::NaiveDateTime; use color_eyre::Result; use ratatui::widgets::TableState; use ratatui_textarea::TextArea; use unidecode::unidecode; use crate::{ config::{Config, Location}, message::Message, update::update, }; /// App-wide Elm model. #[derive(Debug)] pub(crate) struct Model<'a> { pub(crate) config: Config, pub(crate) table_state: TableState, pub(crate) table_rows: Vec>, pub(crate) running_state: RunningState, pub(crate) focus_state: FocusState, pub(crate) filter_textarea: TextArea<'a>, } impl<'a> Model<'a> { /// Create new model from parsed runtime config. pub(crate) fn from_config(config: Config) -> Self { Self { config, table_state: Default::default(), table_rows: Default::default(), running_state: Default::default(), focus_state: Default::default(), filter_textarea: Default::default(), } } /// Run Elm updates until they produce no further recursive messages. pub(crate) fn update_loop(&mut self, msg: Option) -> Result<()> { let mut maybe_msg = msg; while let Some(msg) = maybe_msg { maybe_msg = update(self, msg)?; } Ok(()) } /// Compute list of visible locations based on filter value. pub(crate) fn get_visible_locations(&self) -> Vec { if self.focus_state == FocusState::Filter { let filter_terms = self.get_filter_terms(); self.config .locations .iter() .enumerate() .filter(|(i, location)| { *i == 0 || filter_terms.iter().any(|filter_term| { unidecode(&location.name.to_ascii_lowercase()) .contains(&unidecode(&filter_term.to_ascii_lowercase())) }) }) .map(|(_, value)| value.clone()) .collect() } else { self.config.locations.to_vec() } } fn get_filter_terms(&self) -> Vec { self.filter_textarea .clone() .into_lines() .into_iter() .next() .unwrap_or_default() .split('|') .map(|value| value.trim().to_owned()) .collect() } } #[derive(Debug, Default, Eq, PartialEq)] pub(crate) enum RunningState { #[default] Running, Done, } #[derive(Debug, Default, Eq, PartialEq)] pub(crate) enum FocusState { #[default] Table, Filter, } /// Computed data required to render a timetable cell. #[derive(Debug)] pub(crate) struct CellData { pub(crate) is_daylight: bool, pub(crate) is_current_time: bool, pub(crate) datetime: NaiveDateTime, }