feat: word list UI implemented

This commit is contained in:
2026-08-03 00:03:11 +02:00
parent 09d5deebb1
commit 8231ae3ad1
2 changed files with 52 additions and 24 deletions

View File

@@ -46,9 +46,4 @@ fn main() -> io::Result<()> {
)); ));
} }
} }
Err(Error::new(
io::ErrorKind::Interrupted,
"Exit with abnormal procedure.",
))
} }

View File

@@ -8,7 +8,7 @@ use ratatui::{
layout::{Constraint, Direction, Flex, Layout}, layout::{Constraint, Direction, Flex, Layout},
style::{Color, Style}, style::{Color, Style},
text::Text, text::Text,
widgets::{Block, Borders, Paragraph}, widgets::{Block, Borders, List, ListDirection, ListItem, ListState, Padding, Paragraph},
}; };
use std::io; use std::io;
@@ -22,10 +22,14 @@ pub enum UiState {
DELETE, DELETE,
} }
pub struct Preferences {
help: bool,
}
pub struct App { pub struct App {
state: UiState, state: UiState,
file_database: FileDatabase, file_database: FileDatabase,
scroll_position: usize, list_state: ListState,
word_list: Vec<Word>, word_list: Vec<Word>,
word_filter: Option<String>, word_filter: Option<String>,
lang_filter: Option<String>, lang_filter: Option<String>,
@@ -39,7 +43,7 @@ impl App {
Self { Self {
state: UiState::LIST, state: UiState::LIST,
file_database: db, file_database: db,
scroll_position: 0, list_state: ListState::default().with_selected(Some(0)),
word_list: wl, word_list: wl,
word_filter: None, word_filter: None,
lang_filter: None, lang_filter: None,
@@ -58,7 +62,7 @@ impl App {
Ok(()) Ok(())
} }
fn draw(&self, frame: &mut Frame) { fn draw(&mut self, frame: &mut Frame) {
let main_layout = Layout::default() let main_layout = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.spacing(0) .spacing(0)
@@ -109,13 +113,35 @@ impl App {
filters_layout[1], filters_layout[1],
); );
frame.render_widget( let word_key_list_items: Vec<ListItem> = self
Paragraph::new("Word list").block(Block::new().borders(Borders::ALL).title("Entries")), .word_list
words_layout[0], .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 // 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 { if let Some(w) = selected_word {
frame.render_widget( frame.render_widget(
Paragraph::new(w.description).block(Block::new().borders(Borders::ALL)), 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)); .style(Style::new().fg(Color::DarkGray));
let help_area = help_layout[0].centered( let help_area = help_layout[0].centered(
Constraint::Length(help_text.width() as u16), Constraint::Length(help_text.width() as u16),
@@ -148,7 +174,7 @@ impl App {
self.file_database.get_all_words() self.file_database.get_all_words()
} }
}; };
self.scroll_position = 0; self.list_state.select(Some(0));
self.word_list = word_list; self.word_list = word_list;
} }
@@ -184,7 +210,7 @@ impl App {
if c == 'f' || c == '/' { if c == 'f' || c == '/' {
self.state = UiState::FILTERWORD; self.state = UiState::FILTERWORD;
} }
if c == 'g' { if c == 'l' {
self.state = UiState::FILTERLANG; self.state = UiState::FILTERLANG;
} }
if c == 'd' { if c == 'd' {
@@ -198,14 +224,10 @@ impl App {
} }
// Movement // Movement
if c == 'j' { if c == 'j' {
if self.scroll_position > 0 { self.list_state.select_next();
self.scroll_position -= 1;
}
} }
if c == 'k' { if c == 'k' {
if self.scroll_position < self.word_list.len() - 1 { self.list_state.select_previous();
self.scroll_position += 1;
}
} }
} }
} }
@@ -223,7 +245,18 @@ impl App {
self.update_word_list(); 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 => { event::KeyCode::Esc => {