use color_eyre::Result; use ratatui::{ layout::{Alignment, Rect}, text::Line, widgets::{Block, Padding, Paragraph, Wrap}, Frame, }; use super::{Component, CurrentTab}; use crate::{ components::generic::PartialComponent, config::Config, action::Action, palette::StylePalette, widgets::{PixelSize, BigText}, }; #[derive(Debug, Default)] pub struct CurrentEpoch { number: u64, progress: u64, palette: StylePalette, } impl CurrentEpoch { const SECONDS_IN_BLOCK: u64 = 6; const SESSION_LENGTH: u64 = 2_400; const SECONDS_IN_DAY: u64 = 86_400; const SECONDS_IN_HOUR: u64 = 3_600; } impl PartialComponent for CurrentEpoch {} impl Component for CurrentEpoch { fn register_config_handler(&mut self, config: Config) -> Result<()> { if let Some(style) = config.styles.get(&crate::app::Mode::Explorer) { self.palette.with_normal_style(style.get("normal_style").copied()); self.palette.with_hover_style(style.get("hover_style").copied()); self.palette.with_normal_border_style(style.get("normal_border_style").copied()); self.palette.with_hover_border_style(style.get("hover_border_style").copied()); self.palette.with_normal_title_style(style.get("normal_title_style").copied()); self.palette.with_hover_title_style(style.get("hover_title_style").copied()); } Ok(()) } fn update(&mut self, action: Action) -> Result> { match action { Action::SetEpochProgress(number, progress) => { self.number = number; self.progress = progress; }, _ => {} }; Ok(None) } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { let [place, _] = super::layouts::explorer_era_info_layout(area); let seconds_to_next = Self::SESSION_LENGTH.saturating_sub(self.progress) * Self::SECONDS_IN_BLOCK; let hours = (seconds_to_next % Self::SECONDS_IN_DAY) / Self::SECONDS_IN_HOUR; let minutes = (seconds_to_next % Self::SECONDS_IN_HOUR) / 60; let seconds = seconds_to_next % 60; let text = self.number.to_string(); let big_time = hours > 0; let (border_style, border_type) = self.palette.create_border_style(false); let height = place.as_size().height; let width = place.as_size().width; let text_width = text.len() as u16 * 4 + 2; if width < text_width || height < 7 { let text = vec![ Line::from(text), Line::from(format!("{}{} {}{}", if big_time { hours } else { minutes }, if big_time { "hrs" } else { "mins" }, if big_time { minutes } else { seconds }, if big_time { "mins" } else { "secs" })), ]; let paragraph = Paragraph::new(text) .block(Block::bordered() .border_style(border_style) .border_type(border_type) .title_alignment(Alignment::Right) .title_style(self.palette.create_title_style(false)) .padding(Padding::new(0, 0, height.saturating_sub(3) / 2, 0)) .title("Epoch")) .alignment(Alignment::Center) .wrap(Wrap { trim: true }); frame.render_widget(paragraph, place); } else { let big_text = BigText::builder() .centered() .pixel_size(PixelSize::Quadrant) .style(self.palette.create_basic_style(false)) .lines(vec![ text.into(), ]) .build(); let paragraph = Paragraph::new("") .block(Block::bordered() .border_style(border_style) .border_type(border_type) .title_style(self.palette.create_title_style(false)) .title_top(Line::from("Epoch").right_aligned()) .title_top(Line::from(format!("{}{} {}{}", if big_time { hours } else { minutes }, if big_time { "hrs" } else { "mins" }, if big_time { minutes } else { seconds }, if big_time { "mins" } else { "secs" })) .centered())) .alignment(Alignment::Center) .wrap(Wrap { trim: true }); frame.render_widget(paragraph, place); let height_offset = height.saturating_sub(2) / 2; let place = place.offset(ratatui::layout::Offset { x: 1, y: height_offset as i32 }) .intersection(place); frame.render_widget(big_text, place); } Ok(()) } }