From fd86cb35500fcc693bfb99cd8a1ae6011eda7443 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 5 May 2026 14:26:34 +0300 Subject: [PATCH] Word groups works --- src/data_provider/words.rs | 52 +++++++++++- src/dictionary.rs | 162 ++++++++++++++++++++++++++++++++----- src/lang.rs | 1 + 3 files changed, 192 insertions(+), 23 deletions(-) diff --git a/src/data_provider/words.rs b/src/data_provider/words.rs index 5202248..af20a0b 100644 --- a/src/data_provider/words.rs +++ b/src/data_provider/words.rs @@ -67,12 +67,14 @@ fn create_tables(conn: &Connection) { pub fn add_word(word: &mut WordData, connection: &Connection) { let index = connection .query_row( - "INSERT INTO words (key, value, tags, more) VALUES (?1, ?2, ?3, ?4) RETURNING id", + "INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5\ + ) RETURNING id", ( &word.key, &word.value, &word.tags, serde_json::to_string(&word.additional).unwrap(), + &word.group_id, ), |row| row.get(0), ) @@ -163,4 +165,52 @@ pub fn load_word_groups(connection: &Connection) -> Vec { } buffer +} + +pub fn add_group(group: &mut WordGroup, connection: &Connection) { + let index = connection + .query_row( + "INSERT INTO word_group (name) VALUES (?1) RETURNING id", + ( + &group.name, + ), + |row| row.get(0), + ) + .unwrap_or_else(|e| { + println!("{}", e); + 0 + }); + + group.id = index; +} + +pub fn update_group(group: &mut WordGroup, connection: &Connection) { + if group.id == 0 { + add_group(group, &connection); + } else { + connection + .execute( + "UPDATE word_group SET name = ?1 WHERE id = ?5", + ( + &group.name, + &group.id, + ), + ) + .unwrap_or_else(|e| { + println!("{}", e); + 0 + }); + } +} + +pub fn delete_group(group: &WordGroup, connection: &Connection) { + if group.id == 0 { + return; + } + connection + .execute("DELETE FROM word_group WHERE id = ?1", (&group.id,)) + .unwrap_or_else(|e| { + println!("{}", e); + 0 + }); } \ No newline at end of file diff --git a/src/dictionary.rs b/src/dictionary.rs index 74d98bd..47dc8cb 100644 --- a/src/dictionary.rs +++ b/src/dictionary.rs @@ -1,14 +1,19 @@ -use crate::data_provider::words::{delete_word, update_word}; -use crate::dictionary::DictionaryMessage::Test; +use crate::data_provider::words::{delete_group, delete_word, update_group, update_word}; +use crate::dictionary::DictionaryMessage::{ + ChangeDirection, DeleteGroup, EditGroup, SaveGroup, Test, +}; use crate::dictionary_test::DictionaryQuizState; -use crate::lang::WordData; +use crate::lang::{WordData, WordGroup}; use crate::word::WordState; use crate::Page::Word; use crate::{AppState, NavigatedPage, Page, RootMessage, DEFAULT_SPACING}; use iced::alignment::Vertical::Center; use iced::widget::button::Style; +use iced::widget::button::{danger, text}; +use iced::widget::space::horizontal; use iced::widget::*; use iced::{Border, Color, Length, Shadow, Task}; +use rand::random_range; use std::collections::HashMap; use std::fs; use std::path::PathBuf; @@ -23,6 +28,8 @@ pub struct DictionaryState { reverse: bool, search: String, no_typing: bool, + selected_group_index: usize, + reverse_list: bool, } #[derive(Debug, Clone)] @@ -41,7 +48,12 @@ pub enum DictionaryMessage { SetReverse(bool), Search(String), SetTyping(bool), - + CreateGroup, + EditGroup(String), + SaveGroup, + SelectGroup(usize), + DeleteGroup, + ChangeDirection, } impl NavigatedPage for DictionaryState { @@ -67,7 +79,7 @@ impl NavigatedPage for DictionaryState { } } if let DictionaryMessage::WordAction(index) = message { - let word : WordData; + let word: WordData; { let state = self.state.lock().unwrap(); let dict = &state.dictionary; @@ -84,13 +96,16 @@ impl NavigatedPage for DictionaryState { impl DictionaryState { pub fn new(state: Arc>) -> Self { let len = state.lock().unwrap().dictionary.len(); + let mut result = DictionaryState { include_map: vec![false; len], + selected_group_index: 0, state, tag_map: HashMap::new(), reverse: false, search: "".to_string(), no_typing: false, + reverse_list: true, }; result.update_tags(); @@ -101,8 +116,12 @@ impl DictionaryState { pub fn update(&mut self, message: DictionaryMessage) -> Task { match message { DictionaryMessage::NewWord => { - let dict = &mut self.state.lock().unwrap().dictionary; - dict.push(WordData::new()); + let mut state = self.state.lock().unwrap(); + let mut word = WordData::new(); + word.group_id = state.word_groups[self.selected_group_index].id.clone(); + + let dict = &mut state.dictionary; + dict.push(word); self.include_map.push(false); } @@ -152,7 +171,55 @@ impl DictionaryState { update_word(word, &connection); state.dictionary[i] = word.clone(); } - _ => {} + Back => {} + Test => {} + DictionaryMessage::CreateGroup => { + let state = &mut self.state.lock().unwrap(); + + state.word_groups.push(WordGroup { + id: 0, + name: format!("Группа слов {}", random_range(100..1000)), + }); + } + EditGroup(new) => { + let state = &mut self.state.lock().unwrap(); + let group = state.word_groups.get_mut(self.selected_group_index); + if let Some(group) = group { + group.name = new.clone(); + } + } + SaveGroup => { + let state = &mut self.state.lock().unwrap(); + let connection = &state.connection; + let group = &mut state + .word_groups + .get(self.selected_group_index) + .unwrap() + .clone(); + + update_group(group, connection); + state.word_groups[self.selected_group_index] = group.clone(); + } + DictionaryMessage::SelectGroup(i) => { + self.selected_group_index = i; + } + DeleteGroup => { + if self.selected_group_index == 0 { + return Task::none(); + } + let state = &mut self.state.lock().unwrap(); + + if let Some(group) = state.word_groups.get(self.selected_group_index) { + let connection = &state.connection; + + delete_group(group, connection); + state.word_groups.remove(self.selected_group_index); + self.selected_group_index = 0; + } + } + ChangeDirection => { + self.reverse_list = !self.reverse_list; + } } Task::none() @@ -163,6 +230,7 @@ impl DictionaryState { row![ iced::widget::column![ button("Назад").on_press(Back), + self.groups_panel(), self.words_list(), button("Добавить слово").on_press(DictionaryMessage::NewWord), ] @@ -178,19 +246,31 @@ impl DictionaryState { fn words_list(&self) -> iced::Element<'_, DictionaryMessage> { let mut col = Column::new().width(Length::Fill); - let mut i = 0; - let dict = &self.state.lock().unwrap().dictionary; + let mut range = (0..self.include_map.len()).collect::>(); + let state = self.state.lock().unwrap(); + let group_id = state.word_groups[self.selected_group_index].id; + let dict = &mut state.dictionary.clone(); + + if self.reverse_list { + dict.reverse() + } else { + range = range.iter().rev().map(|x| *x).collect::>(); + } for word in dict { + let i = range.pop().unwrap(); if !self.search.is_empty() { if word.key.contains(&self.search) == false && word.value.contains(&self.search) == false { - i += 1; continue; } } + if word.group_id != group_id { + continue; + } + let mut line = Row::new().width(Length::Fill).align_y(Center); line = line .push( @@ -222,27 +302,26 @@ impl DictionaryState { ); let line_button = || { + let action = DictionaryMessage::WordAction(i); + if word.id == 0 { - return button("-") - .on_press_with(move || DictionaryMessage::WordAction(i)) - .style(|_x, _status| Style { - background: None, - text_color: Color::BLACK, - border: Border::default(), - shadow: Shadow::default(), - snap: false, - }); + return button("-").on_press(action).style(|_x, _status| Style { + background: None, + text_color: Color::BLACK, + border: Border::default(), + shadow: Shadow::default(), + snap: false, + }); } button("") - .on_press_with(move || DictionaryMessage::WordAction(i)) + .on_press(DictionaryMessage::WordAction(i)) .width(15) }; line = line.push(line_button()).push(space().width(10)); col = col.push(line); - i += 1; } scrollable(col).height(Length::Fill).into() @@ -352,6 +431,45 @@ impl DictionaryState { } } } + + fn groups_panel(&self) -> iced::Element<'_, DictionaryMessage> { + let mut row = Row::new(); + row = row.push( + button("+") + .style(text) + .on_press(DictionaryMessage::CreateGroup), + ); + + let state = &self.state.lock().unwrap(); + let groups = &state.word_groups; + + let mut index = 0; + for group in groups { + row = row.push( + button(text!("{}", group.name.clone())) + .style(text) + .on_press(DictionaryMessage::SelectGroup(index)), + ); + index = index + 1; + } + + let group = state.word_groups[self.selected_group_index].clone(); + + iced::widget::column![ + scrollable(row).width(Length::Fill).horizontal(), + row![ + button("⇳").on_press(ChangeDirection), + text_input("Название группы слов", &group.name) + .on_input(EditGroup) + .width(250) + .on_submit(SaveGroup), + horizontal(), + button("Удалить").style(danger).on_press(DeleteGroup), + ] + .spacing(DEFAULT_SPACING) + ] + .into() + } } pub fn split_with_coma(ts: String) -> Vec { diff --git a/src/lang.rs b/src/lang.rs index a8b8bfb..8629340 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -251,6 +251,7 @@ impl WordData { } } +#[derive(Clone)] pub struct WordGroup{ pub id: u32, pub name: String,