diff options
Diffstat (limited to 'src/gui')
| -rw-r--r-- | src/gui/gui.rs | 98 | ||||
| -rw-r--r-- | src/gui/message.rs | 7 | ||||
| -rw-r--r-- | src/gui/mod.rs | 95 | ||||
| -rw-r--r-- | src/gui/question.rs | 90 | ||||
| -rw-r--r-- | src/gui/util.rs | 2 | 
5 files changed, 140 insertions, 152 deletions
| diff --git a/src/gui/gui.rs b/src/gui/gui.rs deleted file mode 100644 index 92b1a72..0000000 --- a/src/gui/gui.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::deck; -use crate::util::time; -use crate::{db::db, gui::message, gui::question, space_repetition, util::event::Events}; -use anyhow::Result; -use rusqlite::Connection; -use std::{fs, io, time::Duration}; -use termion::{raw::IntoRawMode, raw::RawTerminal, screen::AlternateScreen}; -use tui::{backend::TermionBackend, Terminal}; - -type Term = Terminal<TermionBackend<AlternateScreen<RawTerminal<io::Stdout>>>>; - -pub fn terminal() -> Result<Term> { -    let stdout = io::stdout().into_raw_mode()?; -    let stdout = AlternateScreen::from(stdout); -    let backend = TermionBackend::new(stdout); -    Ok(Terminal::new(backend)?) -} - -pub fn synchronize( -    conn: &Connection, -    term: &mut Term, -    events: &Events, -    deck_path: &str, -    deck_name: &str, -) -> Result<()> { -    let last_modified = time::seconds_since_unix_epoch_of(fs::metadata(deck_path)?.modified()?)?; -    let last_deck_read = db::last_deck_read(&conn); -    let must_synchronize = last_deck_read.map(|r| r < last_modified).unwrap_or(true); - -    if must_synchronize { -        let _ = message::show(term, events, &deck_name, "Synchronization du deck…", false); -        time::wait_at_least( -            || db::synchronize(&conn, deck::read(&deck_path)?), -            Duration::from_secs(1), -        )?; -    } - -    Ok(()) -} - -pub fn start( -    conn: &Connection, -    term: &mut Term, -    events: &Events, -    deck_name: &String, -) -> 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)); - -        match db::pick_random_ready(&conn) { -            Some(card) => { -                let difficulty = question::ask(term, events, &title, &card)?; -                answers += 1; -                db::update( -                    &conn, -                    &card.question, -                    &space_repetition::update(card.state, difficulty), -                )?; -            } -            None => { -                let message = match db::next_ready(&conn) { -                    Some(ready) => format!( -                        "Prochaine carte disponible dans {}.", -                        time::pp_duration(ready - now) -                    ), -                    None => format!("Aucune carte n’est disponible. Votre deck est-il vide ?"), -                }; -                let _ = message::show(term, events, &title, &message, true); -                break; -            } -        } -    } - -    Ok(()) -} - -fn title(deck_name: &String, answers: i32, available_cards: i32) -> String { -    if answers == 0 && available_cards == 0 { -        deck_name.to_string() -    } else if available_cards == 0 { -        format!( -            "{} ({} / {})", -            deck_name, -            answers, -            answers + available_cards -        ) -    } else { -        format!( -            "{} ({} / {})", -            deck_name, -            answers + 1, -            answers + available_cards -        ) -    } -} diff --git a/src/gui/message.rs b/src/gui/message.rs index 28a1d2c..b938150 100644 --- a/src/gui/message.rs +++ b/src/gui/message.rs @@ -33,11 +33,8 @@ pub fn show<B: Backend>(          })?;          if wait { -            if let Event::Input(key) = events.next()? { -                match key { -                    Key::Char('q') => break, -                    _ => (), -                } +            if let Event::Input(Key::Char('q')) = events.next()? { +                break              }          } else {              break; diff --git a/src/gui/mod.rs b/src/gui/mod.rs index f351eba..92cd943 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -1,4 +1,97 @@ -pub mod gui;  pub mod message;  pub mod question;  pub mod util; + +use crate::deck; +use crate::util::time; +use crate::{db, space_repetition, util::event::Events}; +use anyhow::Result; +use rusqlite::Connection; +use std::{fs, io, time::Duration}; +use termion::{raw::IntoRawMode, raw::RawTerminal, screen::AlternateScreen}; +use tui::{backend::TermionBackend, Terminal}; + +type Term = Terminal<TermionBackend<AlternateScreen<RawTerminal<io::Stdout>>>>; + +pub fn terminal() -> Result<Term> { +    let stdout = io::stdout().into_raw_mode()?; +    let stdout = AlternateScreen::from(stdout); +    let backend = TermionBackend::new(stdout); +    Ok(Terminal::new(backend)?) +} + +pub fn synchronize( +    conn: &Connection, +    term: &mut Term, +    events: &Events, +    deck_path: &str, +    deck_name: &str, +) -> Result<()> { +    let last_modified = time::seconds_since_unix_epoch_of(fs::metadata(deck_path)?.modified()?)?; +    let last_deck_read = db::last_deck_read(conn); +    let must_synchronize = last_deck_read.map(|r| r < last_modified).unwrap_or(true); + +    if must_synchronize { +        let _ = message::show(term, events, deck_name, "Synchronization du deck…", false); +        time::wait_at_least( +            || db::synchronize(conn, deck::read(deck_path)?), +            Duration::from_secs(1), +        )?; +    } + +    Ok(()) +} + +pub fn start(conn: &Connection, term: &mut Term, events: &Events, deck_name: &str) -> 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)); + +        match db::pick_random_ready(conn) { +            Some(card) => { +                let difficulty = question::ask(term, events, &title, &card)?; +                answers += 1; +                db::update( +                    conn, +                    &card.question, +                    &space_repetition::update(card.state, difficulty), +                )?; +            } +            None => { +                let message = match db::next_ready(conn) { +                    Some(ready) => format!( +                        "Prochaine carte disponible dans {}.", +                        time::pp_duration(ready - now) +                    ), +                    None => "Aucune carte n’est disponible. Votre deck est-il vide ?".to_string(), +                }; +                let _ = message::show(term, events, &title, &message, true); +                break; +            } +        } +    } + +    Ok(()) +} + +fn title(deck_name: &str, answers: i32, available_cards: i32) -> String { +    if answers == 0 && available_cards == 0 { +        deck_name.to_string() +    } else if available_cards == 0 { +        format!( +            "{} ({} / {})", +            deck_name, +            answers, +            answers + available_cards +        ) +    } else { +        format!( +            "{} ({} / {})", +            deck_name, +            answers + 1, +            answers + available_cards +        ) +    } +} diff --git a/src/gui/question.rs b/src/gui/question.rs index 211bcda..5f060e3 100644 --- a/src/gui/question.rs +++ b/src/gui/question.rs @@ -28,7 +28,7 @@ enum Answer {  pub fn ask<B: Backend>(      terminal: &mut Terminal<B>,      events: &Events, -    title: &String, +    title: &str,      card: &Card,  ) -> Result<Difficulty> {      let mut state = State { @@ -59,7 +59,7 @@ pub fn ask<B: Backend>(              let question = Paragraph::new(util::center_vertically(chunks[1], &card.question))                  .style(match state.answer {                      Answer::Write => { -                        if state.input == "" { +                        if state.input.is_empty() {                              Style::default().fg(Color::Yellow)                          } else {                              Style::default() @@ -86,47 +86,44 @@ pub fn ask<B: Backend>(                  .wrap(Wrap { trim: true });              f.render_widget(answer, chunks[2]); -            match state.answer { -                Answer::Difficulty { -                    difficulty: selected, -                } => { -                    if !is_correct(&state.input, &card.responses) || card.responses.len() > 1 { -                        let paragraph = Paragraph::new(util::center_vertically( -                            chunks[3], -                            &serialization::words_to_line(&card.responses), -                        )) -                        .alignment(Alignment::Center); -                        f.render_widget(paragraph, chunks[3]); -                    }; +            if let Answer::Difficulty { +                difficulty: selected, +            } = state.answer +            { +                if !is_correct(&state.input, &card.responses) || card.responses.len() > 1 { +                    let paragraph = Paragraph::new(util::center_vertically( +                        chunks[3], +                        &serialization::words_to_line(&card.responses), +                    )) +                    .alignment(Alignment::Center); +                    f.render_widget(paragraph, chunks[3]); +                }; -                    let difficulties = card.state.difficulties(); -                    let l = difficulties.len(); -                    let sep = Span::styled(" • ", Style::default()); -                    let tabs = difficulties -                        .iter() -                        .enumerate() -                        .map(|(i, d)| { -                            let style = if *d == selected { -                                Style::default() -                                    .fg(Color::Yellow) -                                    .add_modifier(Modifier::UNDERLINED) -                            } else { -                                Style::default().add_modifier(Modifier::DIM) -                            }; -                            let d = Span::styled(difficulty::label(*d), style); -                            if i < l - 1 { -                                [d, sep.clone()].to_vec() -                            } else { -                                [d].to_vec() -                            } -                        }) -                        .collect::<Vec<Vec<Span>>>() -                        .concat(); -                    let p = -                        Paragraph::new(Text::from(Spans::from(tabs))).alignment(Alignment::Center); -                    f.render_widget(p, chunks[4]); -                } -                _ => {} +                let difficulties = card.state.difficulties(); +                let l = difficulties.len(); +                let sep = Span::styled(" • ", Style::default()); +                let tabs = difficulties +                    .iter() +                    .enumerate() +                    .map(|(i, d)| { +                        let style = if *d == selected { +                            Style::default() +                                .fg(Color::Yellow) +                                .add_modifier(Modifier::UNDERLINED) +                        } else { +                            Style::default().add_modifier(Modifier::DIM) +                        }; +                        let d = Span::styled(difficulty::label(*d), style); +                        if i < l - 1 { +                            [d, sep.clone()].to_vec() +                        } else { +                            [d].to_vec() +                        } +                    }) +                    .collect::<Vec<Vec<Span>>>() +                    .concat(); +                let p = Paragraph::new(Text::from(Spans::from(tabs))).alignment(Alignment::Center); +                f.render_widget(p, chunks[4]);              }          })?; @@ -171,15 +168,14 @@ pub fn ask<B: Backend>(      }  } -fn is_correct(input: &String, responses: &Vec<String>) -> bool { +fn is_correct(input: &str, responses: &[String]) -> bool {      responses          .iter() -        .map(|r| r.split("(").collect::<Vec<&str>>()[0].trim()) -        .collect::<Vec<&str>>() -        .contains(&input.as_str()) +        .map(|r| r.split('(').collect::<Vec<&str>>()[0].trim()) +        .any(|x| x == input)  } -fn relative_element<T: Clone + PartialEq>(xs: &Vec<T>, x: &T, ri: i32) -> Option<T> { +fn relative_element<T: Clone + PartialEq>(xs: &[T], x: &T, ri: i32) -> Option<T> {      let i = xs.iter().position(|t| t == x)? as i32 + ri;      if i >= 0 && i < xs.len() as i32 {          Some(xs[i as usize].clone()) diff --git a/src/gui/util.rs b/src/gui/util.rs index 38ed1e7..2314aba 100644 --- a/src/gui/util.rs +++ b/src/gui/util.rs @@ -12,7 +12,7 @@ pub fn title(str: &str) -> Paragraph {      )  } -pub fn center_vertically(chunk: Rect, text: &String) -> String { +pub fn center_vertically(chunk: Rect, text: &str) -> String {      let text_lines = text.lines().count();      let chunk_inner_lines: usize = (chunk.height - 2).into();      let blank_lines = chunk_inner_lines - text_lines; | 
