diff --git a/src/dictionary.rs b/src/dictionary.rs index f51f272..80f9c39 100644 --- a/src/dictionary.rs +++ b/src/dictionary.rs @@ -7,6 +7,7 @@ use crate::lang::{WordData, WordGroup}; use crate::word::WordState; use crate::Page::Word; use crate::{AppState, NavigatedPage, Page, RootMessage, DEFAULT_SPACING}; +use chrono::{DateTime, TimeDelta, Utc}; use iced::alignment::Vertical::Center; use iced::widget::button::Style; use iced::widget::button::{danger, text}; @@ -16,8 +17,10 @@ use iced::{Border, Color, Length, Shadow, Task}; use rand::random_range; use std::collections::HashMap; use std::fs; +use std::ops::Add; use std::path::PathBuf; use std::sync::{Arc, Mutex}; +use std::time::Duration; use DictionaryMessage::Back; #[derive(Clone)] @@ -30,6 +33,7 @@ pub struct DictionaryState { no_typing: bool, selected_group_index: usize, reverse_list: bool, + auto_save_queue: HashMap>, } #[derive(Debug, Clone)] @@ -54,6 +58,7 @@ pub enum DictionaryMessage { SelectGroup(usize), DeleteGroup, ChangeDirection, + TrySave(usize), } impl NavigatedPage for DictionaryState { @@ -104,8 +109,9 @@ impl DictionaryState { tag_map: HashMap::new(), reverse: false, search: "".to_string(), - no_typing: false, + no_typing: true, reverse_list: true, + auto_save_queue: HashMap::new(), }; result.update_tags(); @@ -126,12 +132,19 @@ impl DictionaryState { } DictionaryMessage::SetKey(i, v) => { - let dict = &mut self.state.lock().unwrap().dictionary; - dict[i].key = v + { + let dict = &mut self.state.lock().unwrap().dictionary; + dict[i].key = v; + } + return self.launch_auto_save_offset(i) } DictionaryMessage::SetValue(i, v) => { - let dict = &mut self.state.lock().unwrap().dictionary; - dict[i].value = v + { + let dict = &mut self.state.lock().unwrap().dictionary; + dict[i].value = v + } + return self.launch_auto_save_offset(i) + } DictionaryMessage::SetTags(i, v) => { { @@ -140,6 +153,7 @@ impl DictionaryState { } self.update_tags(); + return self.launch_auto_save_offset(i) } DictionaryMessage::WordAction(i) => { @@ -147,12 +161,18 @@ impl DictionaryState { let dict = &mut state.dictionary; let word = dict.remove(i); self.include_map.remove(i); + self.auto_save_queue.remove(&i); delete_word(&word, &state.connection) } DictionaryMessage::Include(i, b) => self.include_map[i] = b, DictionaryMessage::IncludeTag(t, v) => { + let index : u32; + { + let mut state = self.state.lock().unwrap(); + index = state.word_groups[self.selected_group_index].id; + } self.tag_map.insert(t, v); - self.update_words_include() + self.update_words_include(index) } DictionaryMessage::ResetTags => { @@ -165,12 +185,7 @@ impl DictionaryState { } DictionaryMessage::SetTyping(b) => self.no_typing = b, DictionaryMessage::SubmitWord(i) => { - let state = &mut self.state.lock().unwrap(); - let connection = &state.connection; - let word = &mut state.dictionary.get(i).unwrap().clone(); - - update_word(word, &connection); - state.dictionary[i] = word.clone(); + self.save_word(i) } Back => {} Test => {} @@ -203,6 +218,13 @@ impl DictionaryState { } DictionaryMessage::SelectGroup(i) => { self.selected_group_index = i; + let index : u32; + { + let state = self.state.lock().unwrap(); + index = state.word_groups[i].id; + } + self.update_words_include(index) + } DeleteGroup => { if self.selected_group_index == 0 { @@ -220,12 +242,36 @@ impl DictionaryState { } ChangeDirection => { self.reverse_list = !self.reverse_list; + }, + DictionaryMessage::TrySave(word_index) => { + let now = Utc::now(); + if !self.auto_save_queue.contains_key(&word_index) { return Task::none(); } + if self.auto_save_queue[&word_index] <= now { + self.auto_save_queue.remove(&word_index); + self.save_word(word_index); + } } } Task::none() } + fn save_word(&mut self, i: usize) { + let state = &mut self.state.lock().unwrap(); + let connection = &state.connection; + let word = &mut state.dictionary.get(i).unwrap().clone(); + + update_word(word, &connection); + state.dictionary[i] = word.clone(); + } + + fn launch_auto_save_offset(&mut self, index: usize) -> Task { + let save_time = Utc::now().add(TimeDelta::milliseconds(2800)); + self.auto_save_queue.insert(index, save_time); + let message = RootMessage::Dictionary(DictionaryMessage::TrySave(index)); + Task::perform(async { tokio::time::sleep(Duration::from_secs(3)).await }, |_| message) + } + pub fn view(&self) -> iced::Element<'_, DictionaryMessage> { container( row![ @@ -281,14 +327,14 @@ impl DictionaryState { .push(space().width(10)); line = line.push( - text_input("Ключ", &word.key) + text_input("Слово", &word.key) .size(20) .width(Length::Fill) .on_input(move |string| DictionaryMessage::SetKey(i, string)) .on_submit(DictionaryMessage::SubmitWord(i)), ); line = line.push( - text_input("Значение", &word.value) + text_input("Перевод", &word.value) .size(20) .width(Length::Fill) .on_input(move |string| DictionaryMessage::SetValue(i, string)) @@ -408,7 +454,7 @@ impl DictionaryState { } } - fn update_words_include(&mut self) { + fn update_words_include(&mut self, group_id: u32) { let include_tags = self .tag_map .iter() @@ -425,7 +471,7 @@ impl DictionaryState { for i in 0..self.include_map.len() { let tags = split_with_coma(dict[i].tags.clone()); - if tags.iter().all(|t| include_tags.contains(t)) { + if tags.iter().all(|t| include_tags.contains(t)) && dict[i].group_id == group_id { self.include_map[i] = true; } else { self.include_map[i] = false; diff --git a/src/repetitions.rs b/src/repetitions.rs index 61199f1..0180eaf 100644 --- a/src/repetitions.rs +++ b/src/repetitions.rs @@ -265,6 +265,8 @@ impl CardSetSettings { let ast = ast.unwrap(); + let groups = &state.word_groups; + for word in &state.dictionary { let mut more = rhai::Map::new(); for iced in &word.additional { @@ -275,7 +277,8 @@ impl CardSetSettings { .push_constant("key", word.key.clone()) .push_constant("value", word.value.clone()) .push_constant("tags", word.tags.clone()) - .push_constant("more", more); + .push_constant("more", more) + .push_constant("group", groups.iter().find(|g| g.id == word.group_id).cloned().unwrap().name); let result = engine.eval_ast_with_scope::(&mut scope, &ast); if result.is_ok() && result.unwrap() { diff --git a/src/word.rs b/src/word.rs index 8efdf3c..13f8823 100644 --- a/src/word.rs +++ b/src/word.rs @@ -58,10 +58,7 @@ impl WordState { } WordMessage::SetAdditional(key, value) => { match key.as_str() { - "reading" => { - self.word.additional.insert(key, value.clone()); - }, - _ => todo!() + _ => { self.word.additional.insert(key, value.clone());} } }, @@ -77,6 +74,9 @@ impl WordState { if !self.word.additional.contains_key("reading") { fast_add = fast_add.push(button("Чтение").style(button::text).on_press(WordMessage::AddAdditional("reading".to_string()))); } + if !self.word.additional.contains_key("description") { + fast_add = fast_add.push(button("Описание").style(button::text).on_press(WordMessage::AddAdditional("description".to_string()))); + } let mut col = iced::widget::column![ button("Назад").on_press(WordMessage::Back), text!("Ключ"), @@ -112,6 +112,7 @@ impl WordState { fn get_view_for_more(&self, value: (&String, &String)) -> Element<'_, WordMessage> { match value.0.as_str() { "reading" => self.reading_field(value), + "description" => self.description_field(value), _ => space().into(), } } @@ -124,6 +125,14 @@ impl WordState { ].spacing(DEFAULT_SPACING) .into() } + + fn description_field(&self, value: (&String, &String)) -> Element<'_, WordMessage> { + column![ + text!("Описание"), + text_input("description", &value.1) + .on_input(|string| WordMessage::SetAdditional("description".to_string(), string)) + ].spacing(DEFAULT_SPACING) + .into() } } #[derive(Debug, Clone)] pub enum WordMessage {