use crate::components::stats::{
ActivePane, STATS_DEFAULT_COL_WIDTH, STATS_FIRST_COL_WIDTH, StatsState, TeamOrPlayer,
};
use mlbt_api::client::StatGroup;
use tui::prelude::*;
use tui::widgets::{Block, BorderType, Borders, Cell, Padding, Paragraph, Row, Table, Wrap};
pub const STATS_OPTIONS_WIDTH: u16 = 36;
pub struct StatsWidget {
pub show_options: bool,
}
impl StatefulWidget for StatsWidget {
type State = StatsState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
let constraints = match self.show_options {
true => {
vec![
Constraint::Length(area.width - STATS_OPTIONS_WIDTH), Constraint::Length(STATS_OPTIONS_WIDTH), ]
}
false => vec![Constraint::Percentage(100)],
};
let chunks = Layout::horizontal(constraints).split(area);
let (header, rows) = state.generate_table();
let sort_column = state.sorting.column_name.as_deref().unwrap_or_default();
let header = header
.into_iter()
.map(|name| {
if name == sort_column {
Cell::from(format!("{name} {}", state.sorting.order.arrow_symbol()))
.style(Style::default().bg(Color::Blue))
} else {
Cell::from(name)
}
})
.collect::<Row>()
.height(1)
.style(Style::default().add_modifier(Modifier::BOLD | Modifier::UNDERLINED));
let rows: Vec<Row> = rows.into_iter().map(Row::new).collect();
let mut active = 0;
let mut options = Vec::new();
for (name, stat) in &state.stats {
let selected = match stat.active {
true => {
active += 1;
"[X]"
}
false => "[ ]",
};
options.push(Row::new(vec![
selected.to_string(),
name.clone(),
stat.description.clone(),
]));
}
let mut constraints = vec![Constraint::Length(STATS_DEFAULT_COL_WIDTH); active];
if active == 0 {
constraints.push(Constraint::Length(STATS_FIRST_COL_WIDTH));
} else {
constraints[0] = Constraint::Length(STATS_FIRST_COL_WIDTH);
}
let mut t = Table::new(rows, constraints)
.header(header)
.column_spacing(0)
.block(
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.padding(Padding::new(1, 1, 0, 0))
.title(Span::styled(
state.date_selector.format_date_border_title(),
Style::default().fg(Color::Black).bg(Color::Blue),
)),
);
if state.active_pane == ActivePane::Data {
t = t.row_highlight_style(Style::default().bg(Color::Blue).fg(Color::Black));
}
state.visible_rows = chunks[0].height.saturating_sub(3) as usize;
StatefulWidget::render(t, chunks[0], buf, &mut state.data_state);
if self.show_options {
let selected_style = Style::default().bg(Color::Blue).fg(Color::Black);
let [stats_rect, options_rect] =
Layout::vertical([Constraint::Length(4), Constraint::Percentage(100)])
.areas(chunks[1]);
let (hitting_style, pitching_style) = match state.stat_type.group {
StatGroup::Pitching => (Style::default(), selected_style),
StatGroup::Hitting => (selected_style, Style::default()),
};
let (team_style, player_style) = match state.stat_type.team_player {
TeamOrPlayer::Player => (Style::default(), selected_style),
TeamOrPlayer::Team => (selected_style, Style::default()),
};
let text = vec![
Line::from(vec![
Span::styled("hitting", hitting_style),
Span::raw(" | "),
Span::styled("pitching", pitching_style),
]),
Line::from(vec![
Span::styled("team", team_style),
Span::raw(" | "),
Span::styled("player", player_style),
]),
];
Paragraph::new(text)
.block(
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded),
)
.alignment(Alignment::Center)
.wrap(Wrap { trim: true })
.render(stats_rect, buf);
let widths = [
Constraint::Length(4),
Constraint::Length(6),
Constraint::Length(25),
];
let mut t = Table::new(options, widths).column_spacing(0).block(
Block::default()
.padding(Padding::new(1, 1, 0, 0))
.borders(Borders::ALL)
.border_type(BorderType::Rounded),
);
if state.active_pane == ActivePane::Options {
t = t.row_highlight_style(selected_style);
}
StatefulWidget::render(t, options_rect, buf, &mut state.options_state);
}
}
}