use std::borrow::Cow;
use crate::model::settings::ThemeSettings;
use crate::widgets::history::History;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Paragraph, Widget};
pub struct StatsWidget<'a> {
history: &'a History,
selected_row: Option<usize>,
selected_col: Option<usize>,
}
impl<'a> StatsWidget<'a> {
pub const fn new(history: &'a History) -> Self {
Self {
history,
selected_row: None,
selected_col: None,
}
}
pub const fn with_selection(mut self, row: usize, col: usize) -> Self {
self.selected_row = Some(row);
self.selected_col = Some(col);
self
}
fn fixed_cell(value: Cow<'static, str>) -> Cow<'static, str> {
const CELL_WIDTH: usize = 10;
if value.starts_with("DNF(") {
return Cow::Borrowed("DNF");
}
if value.chars().count() <= CELL_WIDTH {
return value;
}
Cow::Owned(value.chars().take(CELL_WIDTH).collect())
}
#[allow(clippy::similar_names)]
pub fn render(&self, area: Rect, buf: &mut Buffer, theme: &ThemeSettings) {
let block = Block::default()
.title("Stats")
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.border()));
let best_time = self
.history
.get_fastest_time()
.map_or_else(|| Cow::Borrowed("-"), |t| Cow::Owned(t.to_string()));
let current_time = self
.history
.get_latest_time()
.map_or_else(|| Cow::Borrowed("-"), |t| Cow::Owned(t.to_string()));
let best_mo3 = self.history.get_fastest_mo3().unwrap_or(Cow::Borrowed("-"));
let current_mo3 = self.history.get_latest_mo3().unwrap_or(Cow::Borrowed("-"));
let best_ao5 = self.history.get_fastest_ao5().unwrap_or(Cow::Borrowed("-"));
let current_ao5 = self.history.get_latest_ao5().unwrap_or(Cow::Borrowed("-"));
let best_time = Self::fixed_cell(best_time);
let current_time = Self::fixed_cell(current_time);
let best_mo3 = Self::fixed_cell(best_mo3);
let current_mo3 = Self::fixed_cell(current_mo3);
let best_ao5 = Self::fixed_cell(best_ao5);
let current_ao5 = Self::fixed_cell(current_ao5);
let selected_row = self.selected_row;
let selected_col = self.selected_col;
let row_line =
|label: &str, current: Cow<'static, str>, best: Cow<'static, str>, row: usize| {
let current_selected = selected_row == Some(row) && selected_col == Some(0);
let best_selected = selected_row == Some(row) && selected_col == Some(1);
let mut spans = vec![Span::styled(
format!("{label:8}"),
Style::default().fg(theme.text()),
)];
if current_selected {
spans.push(Span::styled(
format!("{current:>10}"),
Style::default()
.bg(theme.selection())
.fg(theme.selection_text()),
));
} else {
spans.push(Span::styled(
format!("{current:>10}"),
Style::default().fg(theme.text()),
));
}
if best_selected {
spans.push(Span::styled(
format!("{best:>10}"),
Style::default()
.bg(theme.selection())
.fg(theme.selection_text()),
));
} else {
spans.push(Span::styled(
format!("{best:>10}"),
Style::default().fg(theme.text()),
));
}
Line::from(spans)
};
let text = vec![
Line::from(Span::styled(
format!("{:8}{:>10}{:>10}", "", "current", "best"),
Style::default().fg(theme.text()),
)),
row_line("time", current_time, best_time, 0),
row_line("mo3", current_mo3, best_mo3, 1),
row_line("ao5", current_ao5, best_ao5, 2),
];
Paragraph::new(text).block(block).render(area, buf);
}
}