Skip to content

Commit

Permalink
render results with dates
Browse files Browse the repository at this point in the history
  • Loading branch information
radlinskii committed Oct 17, 2023
1 parent c885b43 commit 0dfd672
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 98 deletions.
2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"words":["crossterm","ratatui","donkeytype","tempfile","mockall","automock","foobarbaaz","foobarbazqux","withf","rngs","Szewnia","chrono","datetime"],"flagWords":[],"language":"en","version":"0.2"}
{"version":"0.2","language":"en","flagWords":[],"words":["crossterm","ratatui","donkeytype","tempfile","mockall","automock","foobarbaaz","foobarbazqux","withf","rngs","Szewnia","chrono","datetime","Datelike"]}
86 changes: 3 additions & 83 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,13 @@ mod test_results;

use anyhow::{Context, Result};
use clap::Parser;
use crossterm::event::{self, KeyCode};
use crossterm::execute;
use crossterm::terminal::supports_keyboard_enhancement;
use crossterm::{event::KeyEventKind, execute, ExecutableCommand};
use crossterm::{
event::{KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
backend::CrosstermBackend,
style::{Color, Style},
symbols,
text::Span,
widgets::{Axis, Block, Chart, Dataset, GraphType},
Terminal,
};
use ratatui::{backend::CrosstermBackend, Terminal};
use std::io;

use args::Args;
Expand Down Expand Up @@ -124,13 +116,12 @@ fn main() -> anyhow::Result<()> {
match res {
Ok(test_results) => {
if test_results.completed {
if let Err(err) = test_results.render_stats(&mut terminal) {
if let Err(err) = test_results.render_chart(&mut terminal) {
eprintln!("{:?}", err);

restore_terminal(terminal).context("Unable to restore terminal")?;
return Err(err);
}

if test_results.save {
if let Err(err) = test_results.save_to_file() {
eprintln!("{:?}", err);
Expand All @@ -139,13 +130,6 @@ fn main() -> anyhow::Result<()> {
return Err(err);
}
}

if let Err(err) = show_results() {
eprintln!("{:?}", err);

restore_terminal(terminal).context("Unable to restore terminal")?;
return Err(err);
}
} else {
println!("Test not finished.");
}
Expand All @@ -163,70 +147,6 @@ fn main() -> anyhow::Result<()> {
}
}

fn show_results() -> Result<()> {
io::stderr().execute(EnterAlternateScreen)?;
enable_raw_mode()?;
let mut terminal = Terminal::new(CrosstermBackend::new(io::stderr()))?;
terminal.clear()?;

loop {
terminal.draw(|frame| {
let area = frame.size();

let datasets = vec![Dataset::default()
.name("data1")
.marker(symbols::Marker::Dot)
.graph_type(GraphType::Scatter)
.style(Style::default().fg(Color::Cyan))
.data(&[(0.0, 5.0), (1.0, 6.0), (1.5, 6.434)])];

frame.render_widget(
Chart::new(datasets)
.block(Block::default().title("Chart"))
.x_axis(
Axis::default()
.title(Span::styled("X Axis", Style::default().fg(Color::Red)))
.style(Style::default().fg(Color::White))
.bounds([0.0, 10.0])
.labels(
["0.0", "5.0", "10.0"]
.iter()
.cloned()
.map(Span::from)
.collect(),
),
)
.y_axis(
Axis::default()
.title(Span::styled("Y Axis", Style::default().fg(Color::Red)))
.style(Style::default().fg(Color::White))
.bounds([0.0, 10.0])
.labels(
["0.0", "5.0", "10.0"]
.iter()
.cloned()
.map(Span::from)
.collect(),
),
),
area,
);
})?;

if event::poll(std::time::Duration::from_millis(100))? {
if let event::Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {
break;
}
}
}
}

io::stderr().execute(LeaveAlternateScreen)?;
disable_raw_mode()?;
Ok(())
}

/// prepares terminal window for rendering using tui
fn configure_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>, anyhow::Error> {
enable_raw_mode().context("Unable to enable raw mode")?;
Expand Down
135 changes: 121 additions & 14 deletions src/test_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
//! and save those results and configuration of the test to a file.

use anyhow::{Context, Result};
use chrono::{DateTime, Local};
use chrono::{DateTime, Datelike, Local, Timelike};
use crossterm::event::{self, Event, KeyCode};
use ratatui::{
prelude::{Backend, Constraint, Direction, Layout},
widgets::Paragraph,
style::{Style, Stylize},
widgets::{Bar, BarGroup, Block},
widgets::{BarChart, Paragraph},
Terminal,
};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -109,7 +111,7 @@ impl TestResults {
}

/// saves test statistics and configuration to a file in users home directory
pub fn save_to_file(self) -> Result<(), anyhow::Error> {
pub fn save_to_file(&self) -> Result<(), anyhow::Error> {
let results_dir_path = dirs::home_dir()
.context("Unable to get home directory")?
.join(".local")
Expand Down Expand Up @@ -151,10 +153,34 @@ impl TestResults {
Ok(())
}

/// prints statistics in an easy to read format
pub fn render_stats<B: Backend>(&self, terminal: &mut Terminal<B>) -> Result<()> {
terminal
.draw(|frame| {
pub fn render_chart<B: Backend>(&self, terminal: &mut Terminal<B>) -> Result<()> {
let results_dir_path = dirs::home_dir()
.context("Unable to get home directory")?
.join(".local")
.join("share")
.join("donkeytype");

if !results_dir_path.exists() {
create_dir_all(results_dir_path.clone())
.context("Unable to create results directory for results file")?;
}

let results_file_path = results_dir_path.join("donkeytype-results.csv");

let mut reader = csv::Reader::from_path(results_file_path.clone())
.context("Unable to create CSV Reader")?;

let mut records: Vec<TestResults> = reader
.deserialize()
.collect::<Result<_, csv::Error>>()
.context("Unable to deserialize results")?;

records.push(self.clone());

loop {
terminal.draw(|frame| {
let mut records_to_show = records.clone();

let areas = Layout::default()
.direction(Direction::Vertical)
.constraints(
Expand All @@ -169,6 +195,10 @@ impl TestResults {
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(2),
Constraint::Length(12),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Min(1),
Constraint::Length(1),
]
.as_ref(),
Expand Down Expand Up @@ -229,21 +259,91 @@ impl TestResults {
areas[8],
);
}

if let Some(typed_characters_count) = self.typed_characters_count {
frame.render_widget(
Paragraph::new(format!(
"Characters typed after corrections: {}",
typed_characters_count
typed_characters_count,
)),
areas[9],
);
}
frame.render_widget(Paragraph::new("Press <Esc> to quit"), areas[10]);
})
.context("Unable to render stats")?;

loop {
// Poll for key events
let bar_width = 5;
let frame_width = frame.size().width;
let bars_to_show = ((frame_width + 1) / (bar_width + 1)) as usize;

if records.len() >= bars_to_show {
records_to_show = records[records.len() - bars_to_show..].to_vec();
}

frame.render_widget(
BarChart::default()
.block(Block::default().title("Previous chart"))
.bar_width(bar_width)
.bar_gap(1)
.bar_style(Style::new().white().on_black())
.value_style(Style::new().black().on_white())
.label_style(Style::new().yellow())
.data(
BarGroup::default().bars(
&records_to_show
.iter()
.map(|r| {
Bar::default().value(if let Some(wpm) = r.wpm {
wpm as u64
} else {
0
})
})
.collect::<Vec<Bar>>(),
),
),
areas[10],
);
frame.render_widget(
Paragraph::new(
records_to_show
.iter()
.map(|r| {
format!(
"{}:{} ",
fmt_num(r.local_datetime.hour()),
fmt_num(r.local_datetime.minute())
)
})
.collect::<String>(),
),
areas[11],
);
frame.render_widget(
Paragraph::new(
records_to_show
.iter()
.map(|r| {
format!(
"{}/{} ",
fmt_num(r.local_datetime.month()),
fmt_num(r.local_datetime.day())
)
})
.collect::<String>(),
),
areas[12],
);
frame.render_widget(
Paragraph::new(
records_to_show
.iter()
.map(|r| format!("{} ", r.local_datetime.year()))
.collect::<String>(),
),
areas[13],
);
frame.render_widget(Paragraph::new("Press <Esc> to quit"), areas[14]);
})?;

if event::poll(Duration::from_millis(100)).context("Unable to poll for event")? {
if let Event::Key(key) = event::read().context("Unable to read event")? {
match key.code {
Expand All @@ -254,10 +354,17 @@ impl TestResults {
}
}
}

sleep(Duration::from_millis(100));
}

Ok(())
}
}

fn fmt_num(number: u32) -> String {
if number < 10 {
format!("0{}", number)
} else {
format!("{}", number)
}
}

0 comments on commit 0dfd672

Please sign in to comment.