feat: word list UI implemented
This commit is contained in:
@@ -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>,
|
||||
word_filter: Option<String>,
|
||||
lang_filter: Option<String>,
|
||||
@@ -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<ListItem> = 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 => {
|
||||
|
||||
Reference in New Issue
Block a user