diff --git a/Cargo.lock b/Cargo.lock index eb10cb6..4cc60e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -811,7 +811,7 @@ dependencies = [ [[package]] name = "thokr" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap", "crossterm 0.23.2", diff --git a/Cargo.toml b/Cargo.toml index b7dfbab..236d1a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "thokr" description = "a sleek typing tui written in rust" -version = "0.1.0" +version = "0.1.1" readme = "README.md" repository = "https://github.com/coloradocolby/thokr.git" homepage = "https://github.com/coloradocolby/thokr" diff --git a/src/main.rs b/src/main.rs index fd8b694..27dbefb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ mod util; use crate::{lang::Language, thok::Thok}; use clap::{ArgEnum, ErrorKind, IntoApp, Parser}; use crossterm::{ - event::{self, Event, KeyCode}, + event::{self, Event, KeyCode, KeyEvent}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, tty::IsTty, @@ -129,7 +129,10 @@ fn start_tui( mut app: &mut App, ) -> Result<(), Box> { let cli = app.cli.clone(); - let events = get_events(cli.unwrap().number_of_secs.unwrap_or(0) > 0); + + let should_tick = cli.unwrap().number_of_secs.unwrap_or(0) > 0; + + let thok_events = get_thok_events(should_tick); loop { let mut exit_type: ExitType = ExitType::Quit; @@ -138,8 +141,8 @@ fn start_tui( loop { let app = &mut app; - match events.recv()? { - Events::Tick => { + match thok_events.recv()? { + ThokEvent::Tick => { if app.thok.has_started() && !app.thok.has_finished() { app.thok.on_tick(); @@ -149,8 +152,11 @@ fn start_tui( terminal.draw(|f| ui(f, app))?; } } - Events::Input(key) => { - match key { + ThokEvent::Resize => { + terminal.draw(|f| ui(f, app))?; + } + ThokEvent::Key(key) => { + match key.code { KeyCode::Esc => { break; } @@ -174,10 +180,10 @@ fn start_tui( app.thok.calc_results(); } } - true => match key { + true => match key.code { KeyCode::Char('t') => { webbrowser::open(&format!("https://twitter.com/intent/tweet?text={}%20wpm%20%2F%20{}%25%20acc%20%2F%20{:.2}%20sd%0A%0Ahttps%3A%2F%2Fgithub.com%2Fcoloradocolby%2Fthokr", app.thok.wpm, app.thok.accuracy, app.thok.std_dev)) - .unwrap_or_default(); + .unwrap_or_default(); } KeyCode::Char('r') => { exit_type = ExitType::Restart; @@ -214,25 +220,32 @@ fn start_tui( } #[derive(Clone)] -enum Events { - Input(KeyCode), +enum ThokEvent { + Key(KeyEvent), + Resize, Tick, } -fn get_events(should_tick: bool) -> mpsc::Receiver { +fn get_thok_events(should_tick: bool) -> mpsc::Receiver { let (tx, rx) = mpsc::channel(); if should_tick { let tick_x = tx.clone(); thread::spawn(move || loop { - tick_x.send(Events::Tick).unwrap(); + tick_x.send(ThokEvent::Tick).unwrap(); thread::sleep(Duration::from_millis(100)) }); } thread::spawn(move || loop { - if let Event::Key(key) = event::read().unwrap() { - tx.send(Events::Input(key.code)).unwrap(); + match event::read().unwrap() { + Event::Key(key) => { + tx.send(ThokEvent::Key(key)).unwrap(); + } + Event::Resize(_, _) => { + tx.send(ThokEvent::Resize).unwrap(); + } + _ => {} } }); diff --git a/src/ui.rs b/src/ui.rs index 3cd5120..523cbe1 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -9,7 +9,8 @@ use unicode_width::UnicodeWidthStr; use crate::thok::{Outcome, Thok}; -const HORIZONTAL_MARGIN: u16 = 10; +const HORIZONTAL_MARGIN: u16 = 5; +const VERTICAL_MARGIN: u16 = 2; impl Widget for &Thok { fn render(self, area: Rect, buf: &mut Buffer) { @@ -36,7 +37,8 @@ impl Widget for &Thok { let max_chars_per_line = area.width - (HORIZONTAL_MARGIN * 2); let mut prompt_occupied_lines = ((self.prompt.width() as f64 / max_chars_per_line as f64).ceil() + 1.0) as u16; - let time_left_lines = 2; + + let time_left_lines = if self.duration.is_some() { 2 } else { 0 }; if self.prompt.width() <= max_chars_per_line as usize { prompt_occupied_lines = 1; @@ -85,12 +87,15 @@ impl Widget for &Thok { dim_bold_style, )); - let widget = match prompt_occupied_lines { - 1 => Paragraph::new(Spans::from(spans)) - .alignment(Alignment::Center) - .wrap(Wrap { trim: true }), - _ => Paragraph::new(Spans::from(spans)).wrap(Wrap { trim: true }), - }; + let widget = Paragraph::new(Spans::from(spans)) + .alignment(if prompt_occupied_lines == 1 { + // when the prompt is small enough to fit on one line + // centering the text gives a nice zen feeling + Alignment::Center + } else { + Alignment::Left + }) + .wrap(Wrap { trim: true }); widget.render(chunks[2], buf); @@ -107,11 +112,11 @@ impl Widget for &Thok { false => { let chunks = Layout::default() .direction(Direction::Vertical) - .horizontal_margin(10) - .vertical_margin(5) + .horizontal_margin(HORIZONTAL_MARGIN) + .vertical_margin(VERTICAL_MARGIN) .constraints( [ - Constraint::Percentage(90), + Constraint::Min(1), Constraint::Length(1), Constraint::Length(1), // for padding Constraint::Length(1),