diff --git a/src/main.rs b/src/main.rs index 2d3b0ac..eaf6517 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,9 +46,4 @@ fn main() -> io::Result<()> { )); } } - - Err(Error::new( - io::ErrorKind::Interrupted, - "Exit with abnormal procedure.", - )) } diff --git a/src/modules/ui/app.rs b/src/modules/ui/app.rs index 0366de4..6ec341b 100644 --- a/src/modules/ui/app.rs +++ b/src/modules/ui/app.rs @@ -8,7 +8,7 @@ use ratatui::{ layout::{Constraint, Direction, Flex, Layout}, style::{Color, Style}, text::Text, - widgets::{Block, Borders, Paragraph}, + widgets::{Block, Borders, List, ListDirection, ListItem, ListState, Padding, Paragraph}, }; use std::io; @@ -22,10 +22,14 @@ pub enum UiState { DELETE, } +pub struct Preferences { + help: bool, +} + pub struct App { state: UiState, file_database: FileDatabase, - scroll_position: usize, + list_state: ListState, word_list: Vec, word_filter: Option, lang_filter: Option, @@ -39,7 +43,7 @@ impl App { Self { state: UiState::LIST, file_database: db, - scroll_position: 0, + list_state: ListState::default().with_selected(Some(0)), word_list: wl, word_filter: None, lang_filter: None, @@ -58,7 +62,7 @@ impl App { Ok(()) } - fn draw(&self, frame: &mut Frame) { + fn draw(&mut self, frame: &mut Frame) { let main_layout = Layout::default() .direction(Direction::Vertical) .spacing(0) @@ -109,13 +113,35 @@ impl App { filters_layout[1], ); - frame.render_widget( - Paragraph::new("Word list").block(Block::new().borders(Borders::ALL).title("Entries")), - words_layout[0], - ); + let word_key_list_items: Vec = self + .word_list + .clone() + .iter() + .map(|w| ListItem::new(w.key.clone())) + .collect(); + let word_key_list = List::new(word_key_list_items) + .direction(ListDirection::TopToBottom) + .block( + Block::default() + .title("Entries") + .borders(Borders::ALL) + .padding(Padding::horizontal(1)), + ) + .highlight_style(Style::default().fg(Color::default())) + .highlight_symbol("> ") + .style(Style::default().fg(Color::DarkGray)); + frame.render_stateful_widget(word_key_list, words_layout[0], &mut self.list_state); + + let scroll_position: usize = { + if let Some(i) = self.list_state.selected() { + i + } else { + 0 + } + }; // PERF: do not clone - let selected_word = self.word_list.clone().into_iter().nth(self.scroll_position); + let selected_word = self.word_list.clone().into_iter().nth(scroll_position); if let Some(w) = selected_word { frame.render_widget( Paragraph::new(w.description).block(Block::new().borders(Borders::ALL)), @@ -123,7 +149,7 @@ impl App { ); } - let help_text = Text::raw("(f)ilter | lan(g) | (d)elete | (e)dit | (a)dd | (q)uit ") + let help_text = Text::raw("(f)ilter | (l)ang | (d)elete | (e)dit | (a)dd | (q)uit ") .style(Style::new().fg(Color::DarkGray)); let help_area = help_layout[0].centered( Constraint::Length(help_text.width() as u16), @@ -148,7 +174,7 @@ impl App { self.file_database.get_all_words() } }; - self.scroll_position = 0; + self.list_state.select(Some(0)); self.word_list = word_list; } @@ -184,7 +210,7 @@ impl App { if c == 'f' || c == '/' { self.state = UiState::FILTERWORD; } - if c == 'g' { + if c == 'l' { self.state = UiState::FILTERLANG; } if c == 'd' { @@ -198,14 +224,10 @@ impl App { } // Movement if c == 'j' { - if self.scroll_position > 0 { - self.scroll_position -= 1; - } + self.list_state.select_next(); } if c == 'k' { - if self.scroll_position < self.word_list.len() - 1 { - self.scroll_position += 1; - } + self.list_state.select_previous(); } } } @@ -223,7 +245,18 @@ impl App { self.update_word_list(); } } - UiState::FILTERLANG => {} + UiState::FILTERLANG => { + if let Some(l) = &self.lang_filter { + if l.len() <= 1 { + self.lang_filter = None; + } else { + let mut new_l = l.clone(); + new_l.pop(); + self.lang_filter = Some(new_l); + } + self.update_word_list(); + } + } _ => {} }, event::KeyCode::Esc => {