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

@@ -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 => {