use ratatui::Frame;
use ratatui::layout::{Constraint, Layout};
use ratatui::style::Stylize;
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Cell, List, Row, Table};
use crate::prelude::*;
pub struct Trace {
pub target: &'static str,
pub sent: u64,
pub hops: Vec<Hop>,
}
pub struct Hop {
pub host: Option<&'static str>,
pub loss: f64,
pub average: f64,
}
impl Trace {
pub fn sample() -> Trace {
let hop = |host, loss, average| Hop { host, loss, average };
Trace {
target: "example.org",
sent: 1204,
hops: vec![
hop(Some("router.lan"), 0.0, 1.1),
hop(None, 1.0, 0.0),
hop(Some("example.org"), 0.021, 45.6),
],
}
}
fn loss(&self) -> f64 {
self.hops.iter().map(|hop| hop.loss).sum::<f64>() / self.hops.len() as f64
}
}
pub fn draw(frame: &mut Frame, trace: &Trace) {
let [main, hints, status] = Layout::vertical([
Constraint::Fill(1),
Constraint::Length(1),
Constraint::Length(1),
])
.areas(frame.area());
let [hops, menu] =
Layout::horizontal([Constraint::Fill(1), Constraint::Length(16)]).areas(main);
let header = Row::new([
tr!("column.hop"),
tr!("column.host"),
tr!("column.loss"),
tr!("column.average"),
])
.bold();
let rows = trace.hops.iter().enumerate().map(|(i, hop)| {
let host = match hop.host {
Some(name) => Cell::from(name),
None => Cell::from(tr!("cell.no-reply")),
};
Row::new([
Cell::from((i + 1).to_string()),
host,
Cell::from(tr!("cell.loss", share = hop.loss)),
Cell::from(tr!("cell.ms", ms = hop.average)),
])
});
let widths = [
Constraint::Length(3),
Constraint::Fill(1),
Constraint::Length(8),
Constraint::Length(10),
];
let table = Table::new(rows, widths)
.header(header)
.block(Block::bordered().title(tr!("title", target = trace.target)));
frame.render_widget(table, hops);
let items = Locale::ALL.iter().enumerate().map(|(i, &lang)| {
let item = Line::from(vec![Span::raw(format!("{} ", i + 1)), Span::from(lang.name())]);
if lang == current_locale() {
item.bold()
} else {
item
}
});
let list = List::new(items).block(Block::bordered().title(tr!("languages")));
frame.render_widget(list, menu);
frame.render_widget(Line::from(tr!("hints")).right_aligned(), hints);
let summary = tr!(
"status",
hops = trace.hops.len(),
sent = trace.sent,
loss = trace.loss(),
);
frame.render_widget(Line::from(summary), status);
}