aboutsummaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
authorJoris2023-01-26 08:12:13 +0100
committerJoris2023-01-26 08:40:13 +0100
commit417d0cac77ff4e48945bbc3086dd6d5c0c3bda6e (patch)
treeb5ff138092623733c1541f79877cd0b5b8f96d73 /src/gui
parent155d8d96574a5ba141767da1af57afde55fccf6f (diff)
Upgrade dependencies
- Switch to crossterm - add --hide-progress option
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/message.rs15
-rw-r--r--src/gui/mod.rs43
-rw-r--r--src/gui/question.rs69
3 files changed, 68 insertions, 59 deletions
diff --git a/src/gui/message.rs b/src/gui/message.rs
index 29b5d8a..0136f1c 100644
--- a/src/gui/message.rs
+++ b/src/gui/message.rs
@@ -1,7 +1,6 @@
use crate::gui::util;
-use crate::util::event::{Event, Events};
+use crossterm::event::{self, Event, KeyCode, KeyModifiers};
use anyhow::Result;
-use termion::event::Key;
use tui::{
backend::Backend,
layout::{Alignment, Constraint, Direction, Layout},
@@ -11,7 +10,6 @@ use tui::{
pub fn show<B: Backend>(
terminal: &mut Terminal<B>,
- events: &Events,
title: &str,
message: &str,
wait: bool,
@@ -33,14 +31,13 @@ pub fn show<B: Backend>(
})?;
if wait {
- if let Event::Input(key) = events.next()? {
- match key {
- Key::Char('q') | Key::Ctrl('c') => {
- break;
- }
- _ => {}
+ // if crossterm::event::poll(Duration::from_secs(0))? {
+ if let Event::Key(key) = event::read()? {
+ if key.code == KeyCode::Char('q') || key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL) {
+ break;
}
}
+ // }
} else {
break;
}
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index 358e4b5..1053de1 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -2,31 +2,44 @@ pub mod message;
pub mod question;
pub mod util;
-use crate::{db, space_repetition, util::event::Events, util::time};
+use crate::{db, space_repetition, util::time};
use anyhow::Result;
use rusqlite::Connection;
-use std::io;
-use termion::{raw::IntoRawMode, raw::RawTerminal, screen::AlternateScreen};
-use tui::{backend::TermionBackend, Terminal};
+use std::io::Stdout;
+use tui::{backend::CrosstermBackend, Terminal};
+use crossterm::{terminal};
-pub type Term = Terminal<TermionBackend<AlternateScreen<RawTerminal<io::Stdout>>>>;
+pub type Term = Terminal<CrosstermBackend<Stdout>>;
-pub fn terminal() -> Result<Term> {
- let stdout = io::stdout().into_raw_mode()?;
- let stdout = AlternateScreen::from(stdout);
- let backend = TermionBackend::new(stdout);
+pub fn setup_terminal() -> Result<Term> {
+ terminal::enable_raw_mode()?;
+ let mut stdout = std::io::stdout();
+ crossterm::execute!(stdout, terminal::EnterAlternateScreen)?;
+ let backend = CrosstermBackend::new(stdout);
Ok(Terminal::new(backend)?)
}
-pub fn start(conn: &Connection, term: &mut Term, events: &Events, deck_name: &str) -> Result<()> {
+pub fn restore_terminal(term: &mut Term) -> Result<()> {
+ terminal::disable_raw_mode()?;
+ crossterm::execute!(term.backend_mut(), terminal::LeaveAlternateScreen)?;
+ term.show_cursor()?;
+ Ok(())
+}
+
+pub fn start(
+ conn: &Connection,
+ term: &mut Term,
+ deck_name: &str,
+ hide_progress: bool,
+) -> Result<()> {
let mut answers = 0;
loop {
let now = time::seconds_since_unix_epoch()?;
- let title = title(deck_name, answers, db::count_available(conn).unwrap_or(0));
+ let title = title(deck_name, answers, db::count_available(conn).unwrap_or(0), hide_progress);
match db::pick_random_ready(conn) {
- Some(card) => match question::ask(term, events, &title, &card)? {
+ Some(card) => match question::ask(term, &title, &card)? {
question::Response::Aborted => break,
question::Response::Answered { difficulty } => {
answers += 1;
@@ -45,7 +58,7 @@ pub fn start(conn: &Connection, term: &mut Term, events: &Events, deck_name: &st
}
None => "Aucune carte n’est disponible. Votre deck est-il vide ?".to_string(),
};
- let _ = message::show(term, events, &title, &message, true);
+ let _ = message::show(term, &title, &message, true);
break;
}
}
@@ -54,8 +67,8 @@ pub fn start(conn: &Connection, term: &mut Term, events: &Events, deck_name: &st
Ok(())
}
-fn title(deck_name: &str, answers: i32, available_cards: i32) -> String {
- if answers == 0 && available_cards == 0 {
+fn title(deck_name: &str, answers: i32, available_cards: i32, hide_progress: bool) -> String {
+ if answers == 0 && available_cards == 0 || hide_progress {
deck_name.to_string()
} else if available_cards == 0 {
let from = answers;
diff --git a/src/gui/question.rs b/src/gui/question.rs
index 2aa6e65..73e4a93 100644
--- a/src/gui/question.rs
+++ b/src/gui/question.rs
@@ -1,11 +1,10 @@
use crate::{
gui::util,
model::{difficulty, difficulty::Difficulty, Card},
- util::event::{Event, Events},
util::serialization,
};
use anyhow::Result;
-use termion::event::Key;
+use crossterm::event::{self, Event, KeyCode, KeyModifiers};
use tui::{
backend::Backend,
layout::{Alignment, Constraint, Direction, Layout},
@@ -32,7 +31,6 @@ pub enum Response {
pub fn ask<B: Backend>(
terminal: &mut Terminal<B>,
- events: &Events,
title: &str,
card: &Card,
) -> Result<Response> {
@@ -136,10 +134,10 @@ pub fn ask<B: Backend>(
}
})?;
- if let Event::Input(key) = events.next()? {
+ if let Event::Key(key) = event::read()? {
match state.answer {
- Answer::Write => match key {
- Key::Char('\n') => {
+ Answer::Write => match key.code {
+ KeyCode::Char('\n') => {
let difficulty = if is_correct(&state.input, &card.responses) {
Difficulty::Good
} else {
@@ -147,57 +145,58 @@ pub fn ask<B: Backend>(
};
state.answer = Answer::Difficulty { difficulty }
}
- Key::Char(c) => {
- state.input.push(c);
- if is_correct(&state.input, &card.responses) {
- state.answer = Answer::Difficulty {
- difficulty: Difficulty::Good,
+ KeyCode::Char(c) => {
+ if key.modifiers.contains(KeyModifiers::CONTROL) {
+ if c == 'u' {
+ state.input.clear();
+ } else if c == 'w' {
+ let mut words = state.input.split_whitespace().collect::<Vec<&str>>();
+ if !words.is_empty() {
+ words.truncate(words.len() - 1);
+ let joined_words = words.join(" ");
+ let space = if !words.is_empty() { " " } else { "" };
+ state.input = format!("{joined_words}{space}");
+ }
+ } else if c == 'c' {
+ return Ok(Response::Aborted);
+ }
+ } else {
+ state.input.push(c);
+ if is_correct(&state.input, &card.responses) {
+ state.answer = Answer::Difficulty {
+ difficulty: Difficulty::Good,
+ }
}
}
}
- Key::Backspace => {
+ KeyCode::Backspace => {
state.input.pop();
}
- Key::Ctrl('u') => {
- state.input.clear();
- }
- Key::Ctrl('w') => {
- let mut words = state.input.split_whitespace().collect::<Vec<&str>>();
- if !words.is_empty() {
- words.truncate(words.len() - 1);
- state.input = format!(
- "{}{}",
- words.join(" "),
- if !words.is_empty() { " " } else { "" }
- );
- }
- }
- Key::Ctrl('c') => {
- return Ok(Response::Aborted);
- }
_ => {}
},
Answer::Difficulty {
difficulty: selected,
- } => match key {
- Key::Left => {
+ } => match key.code {
+ KeyCode::Left => {
for d in relative_element(&card.state.difficulties(), &selected, -1).iter()
{
state.answer = Answer::Difficulty { difficulty: *d }
}
}
- Key::Right => {
+ KeyCode::Right => {
for d in relative_element(&card.state.difficulties(), &selected, 1).iter() {
state.answer = Answer::Difficulty { difficulty: *d }
}
}
- Key::Char('\n') => {
+ KeyCode::Enter => {
return Ok(Response::Answered {
difficulty: selected,
})
}
- Key::Ctrl('c') => {
- return Ok(Response::Aborted);
+ KeyCode::Char('c') => {
+ if key.modifiers.contains(KeyModifiers::CONTROL) {
+ return Ok(Response::Aborted);
+ }
}
_ => {}
},