Auto save works

This commit is contained in:
2026-05-10 22:15:03 +03:00
parent 6c53bc115a
commit ee817a8e8c
3 changed files with 79 additions and 21 deletions
+59 -13
View File
@@ -7,6 +7,7 @@ use crate::lang::{WordData, WordGroup};
use crate::word::WordState; use crate::word::WordState;
use crate::Page::Word; use crate::Page::Word;
use crate::{AppState, NavigatedPage, Page, RootMessage, DEFAULT_SPACING}; use crate::{AppState, NavigatedPage, Page, RootMessage, DEFAULT_SPACING};
use chrono::{DateTime, TimeDelta, Utc};
use iced::alignment::Vertical::Center; use iced::alignment::Vertical::Center;
use iced::widget::button::Style; use iced::widget::button::Style;
use iced::widget::button::{danger, text}; use iced::widget::button::{danger, text};
@@ -16,8 +17,10 @@ use iced::{Border, Color, Length, Shadow, Task};
use rand::random_range; use rand::random_range;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use std::ops::Add;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::Duration;
use DictionaryMessage::Back; use DictionaryMessage::Back;
#[derive(Clone)] #[derive(Clone)]
@@ -30,6 +33,7 @@ pub struct DictionaryState {
no_typing: bool, no_typing: bool,
selected_group_index: usize, selected_group_index: usize,
reverse_list: bool, reverse_list: bool,
auto_save_queue: HashMap<usize, DateTime<Utc>>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -54,6 +58,7 @@ pub enum DictionaryMessage {
SelectGroup(usize), SelectGroup(usize),
DeleteGroup, DeleteGroup,
ChangeDirection, ChangeDirection,
TrySave(usize),
} }
impl NavigatedPage<DictionaryMessage> for DictionaryState { impl NavigatedPage<DictionaryMessage> for DictionaryState {
@@ -104,8 +109,9 @@ impl DictionaryState {
tag_map: HashMap::new(), tag_map: HashMap::new(),
reverse: false, reverse: false,
search: "".to_string(), search: "".to_string(),
no_typing: false, no_typing: true,
reverse_list: true, reverse_list: true,
auto_save_queue: HashMap::new(),
}; };
result.update_tags(); result.update_tags();
@@ -126,13 +132,20 @@ impl DictionaryState {
} }
DictionaryMessage::SetKey(i, v) => { DictionaryMessage::SetKey(i, v) => {
{
let dict = &mut self.state.lock().unwrap().dictionary; let dict = &mut self.state.lock().unwrap().dictionary;
dict[i].key = v dict[i].key = v;
}
return self.launch_auto_save_offset(i)
} }
DictionaryMessage::SetValue(i, v) => { DictionaryMessage::SetValue(i, v) => {
{
let dict = &mut self.state.lock().unwrap().dictionary; let dict = &mut self.state.lock().unwrap().dictionary;
dict[i].value = v dict[i].value = v
} }
return self.launch_auto_save_offset(i)
}
DictionaryMessage::SetTags(i, v) => { DictionaryMessage::SetTags(i, v) => {
{ {
let dict = &mut self.state.lock().unwrap().dictionary; let dict = &mut self.state.lock().unwrap().dictionary;
@@ -140,6 +153,7 @@ impl DictionaryState {
} }
self.update_tags(); self.update_tags();
return self.launch_auto_save_offset(i)
} }
DictionaryMessage::WordAction(i) => { DictionaryMessage::WordAction(i) => {
@@ -147,12 +161,18 @@ impl DictionaryState {
let dict = &mut state.dictionary; let dict = &mut state.dictionary;
let word = dict.remove(i); let word = dict.remove(i);
self.include_map.remove(i); self.include_map.remove(i);
self.auto_save_queue.remove(&i);
delete_word(&word, &state.connection) delete_word(&word, &state.connection)
} }
DictionaryMessage::Include(i, b) => self.include_map[i] = b, DictionaryMessage::Include(i, b) => self.include_map[i] = b,
DictionaryMessage::IncludeTag(t, v) => { 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.tag_map.insert(t, v);
self.update_words_include() self.update_words_include(index)
} }
DictionaryMessage::ResetTags => { DictionaryMessage::ResetTags => {
@@ -165,12 +185,7 @@ impl DictionaryState {
} }
DictionaryMessage::SetTyping(b) => self.no_typing = b, DictionaryMessage::SetTyping(b) => self.no_typing = b,
DictionaryMessage::SubmitWord(i) => { DictionaryMessage::SubmitWord(i) => {
let state = &mut self.state.lock().unwrap(); self.save_word(i)
let connection = &state.connection;
let word = &mut state.dictionary.get(i).unwrap().clone();
update_word(word, &connection);
state.dictionary[i] = word.clone();
} }
Back => {} Back => {}
Test => {} Test => {}
@@ -203,6 +218,13 @@ impl DictionaryState {
} }
DictionaryMessage::SelectGroup(i) => { DictionaryMessage::SelectGroup(i) => {
self.selected_group_index = 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 => { DeleteGroup => {
if self.selected_group_index == 0 { if self.selected_group_index == 0 {
@@ -220,12 +242,36 @@ impl DictionaryState {
} }
ChangeDirection => { ChangeDirection => {
self.reverse_list = !self.reverse_list; 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() 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<RootMessage> {
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> { pub fn view(&self) -> iced::Element<'_, DictionaryMessage> {
container( container(
row![ row![
@@ -281,14 +327,14 @@ impl DictionaryState {
.push(space().width(10)); .push(space().width(10));
line = line.push( line = line.push(
text_input("Ключ", &word.key) text_input("Слово", &word.key)
.size(20) .size(20)
.width(Length::Fill) .width(Length::Fill)
.on_input(move |string| DictionaryMessage::SetKey(i, string)) .on_input(move |string| DictionaryMessage::SetKey(i, string))
.on_submit(DictionaryMessage::SubmitWord(i)), .on_submit(DictionaryMessage::SubmitWord(i)),
); );
line = line.push( line = line.push(
text_input("Значение", &word.value) text_input("Перевод", &word.value)
.size(20) .size(20)
.width(Length::Fill) .width(Length::Fill)
.on_input(move |string| DictionaryMessage::SetValue(i, string)) .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 let include_tags = self
.tag_map .tag_map
.iter() .iter()
@@ -425,7 +471,7 @@ impl DictionaryState {
for i in 0..self.include_map.len() { for i in 0..self.include_map.len() {
let tags = split_with_coma(dict[i].tags.clone()); 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; self.include_map[i] = true;
} else { } else {
self.include_map[i] = false; self.include_map[i] = false;
+4 -1
View File
@@ -265,6 +265,8 @@ impl CardSetSettings {
let ast = ast.unwrap(); let ast = ast.unwrap();
let groups = &state.word_groups;
for word in &state.dictionary { for word in &state.dictionary {
let mut more = rhai::Map::new(); let mut more = rhai::Map::new();
for iced in &word.additional { for iced in &word.additional {
@@ -275,7 +277,8 @@ impl CardSetSettings {
.push_constant("key", word.key.clone()) .push_constant("key", word.key.clone())
.push_constant("value", word.value.clone()) .push_constant("value", word.value.clone())
.push_constant("tags", word.tags.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::<bool>(&mut scope, &ast); let result = engine.eval_ast_with_scope::<bool>(&mut scope, &ast);
if result.is_ok() && result.unwrap() { if result.is_ok() && result.unwrap() {
+13 -4
View File
@@ -58,10 +58,7 @@ impl WordState {
} }
WordMessage::SetAdditional(key, value) => { WordMessage::SetAdditional(key, value) => {
match key.as_str() { match key.as_str() {
"reading" => { _ => { self.word.additional.insert(key, value.clone());}
self.word.additional.insert(key, value.clone());
},
_ => todo!()
} }
}, },
@@ -77,6 +74,9 @@ impl WordState {
if !self.word.additional.contains_key("reading") { if !self.word.additional.contains_key("reading") {
fast_add = fast_add.push(button("Чтение").style(button::text).on_press(WordMessage::AddAdditional("reading".to_string()))); 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![ let mut col = iced::widget::column![
button("Назад").on_press(WordMessage::Back), button("Назад").on_press(WordMessage::Back),
text!("Ключ"), text!("Ключ"),
@@ -112,6 +112,7 @@ impl WordState {
fn get_view_for_more(&self, value: (&String, &String)) -> Element<'_, WordMessage> { fn get_view_for_more(&self, value: (&String, &String)) -> Element<'_, WordMessage> {
match value.0.as_str() { match value.0.as_str() {
"reading" => self.reading_field(value), "reading" => self.reading_field(value),
"description" => self.description_field(value),
_ => space().into(), _ => space().into(),
} }
} }
@@ -124,6 +125,14 @@ impl WordState {
].spacing(DEFAULT_SPACING) ].spacing(DEFAULT_SPACING)
.into() .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)] #[derive(Debug, Clone)]
pub enum WordMessage { pub enum WordMessage {