diff --git a/src/data_provider/card_sets.rs b/src/data_provider/card_sets.rs index 46c771f..78b9764 100644 --- a/src/data_provider/card_sets.rs +++ b/src/data_provider/card_sets.rs @@ -1,14 +1,14 @@ -use crate::lang::{AppendMode, CardSetSettings, OrderMode}; +use crate::lang::{DeckSettings, OrderMode}; use rusqlite::Connection; -pub fn load_sets(connection: &Connection) -> Vec { +pub fn load_sets(connection: &Connection) -> Vec { let mut stmt = connection .prepare("SELECT id, name, forward, backward, filter FROM card_set") .unwrap(); let iter = stmt .query_map([], |row| { - Ok(CardSetSettings { + Ok(DeckSettings { id: row.get(0)?, name: row.get(1)?, forward: row.get(2)?, @@ -17,7 +17,6 @@ pub fn load_sets(connection: &Connection) -> Vec { count: None, worst_words_list: None, open_mode: OrderMode::Default, - append_mode: AppendMode::Manual, }) }) .unwrap(); @@ -30,7 +29,7 @@ pub fn load_sets(connection: &Connection) -> Vec { buffer } -pub fn add_set(set: &mut CardSetSettings, connection: &Connection) { +pub fn add_set(set: &mut DeckSettings, connection: &Connection) { let index = connection .query_row( "INSERT INTO card_set (name, forward, backward, filter) VALUES (?1, ?2, ?3, ?4) RETURNING id", @@ -47,7 +46,7 @@ pub fn add_set(set: &mut CardSetSettings, connection: &Connection) { set.id = index; } -pub fn update_card_set(set: &mut CardSetSettings, connection: &Connection) { +pub fn update_card_set(set: &mut DeckSettings, connection: &Connection) { if set.id == 0 { add_set(set, connection); } else { @@ -66,7 +65,7 @@ pub fn update_card_set(set: &mut CardSetSettings, connection: &Connection) { } } -pub fn delete_set(set: &CardSetSettings, connection: &Connection) { +pub fn delete_set(set: &DeckSettings, connection: &Connection) { if set.id == 0 { return; } diff --git a/src/data_provider/card_stats.rs b/src/data_provider/card_stats.rs index 048c7b0..3327cb6 100644 --- a/src/data_provider/card_stats.rs +++ b/src/data_provider/card_stats.rs @@ -1,8 +1,8 @@ -use crate::lang::{CardSetSettings, CardStatistics}; +use crate::lang::{DeckSettings, CardStatistics}; use rusqlite::Connection; use std::time::Instant; -pub fn load_stats_of_set(set: &CardSetSettings, connection: &Connection) -> Vec { +pub fn load_stats_of_set(set: &DeckSettings, connection: &Connection) -> Vec { let mut stmt = connection .prepare("SELECT id, word_id, score, last_opened FROM card_stats WHERE set_id = ?1") .unwrap(); diff --git a/src/data_provider/web_api.rs b/src/data_provider/web_api.rs index f73519a..2c07ad1 100644 --- a/src/data_provider/web_api.rs +++ b/src/data_provider/web_api.rs @@ -98,7 +98,8 @@ pub async fn get_web_version(key: &str) -> Result { let id_url = format!("{API_URL}{key}/version"); let client = reqwest::Client::new(); let version = client.get(&id_url).send().await?.text().await?; - Ok(version.parse::().unwrap()) + println!("version: {}", version); + Ok(version.parse::().unwrap_or_default()) } pub async fn get_local_version() -> u32 { diff --git a/src/dictionary.rs b/src/dictionary.rs index 06f12e7..3e00195 100644 --- a/src/dictionary.rs +++ b/src/dictionary.rs @@ -65,7 +65,7 @@ pub enum DictionaryMessage { } impl NavigatedPage for DictionaryState { - fn navigate(&self, message: &DictionaryMessage) -> Option { + fn navigate(&mut self, message: &DictionaryMessage) -> Option { if let Back = message { return Some(Page::PreviousPage); } diff --git a/src/dictionary_test.rs b/src/dictionary_test.rs index 49bafa8..a56e4b4 100644 --- a/src/dictionary_test.rs +++ b/src/dictionary_test.rs @@ -35,7 +35,7 @@ pub enum DictionaryQuizMessage { } impl NavigatedPage for DictionaryQuizState { - fn navigate(&self, message: &DictionaryQuizMessage) -> Option { + fn navigate(&mut self, message: &DictionaryQuizMessage) -> Option { match message { Back => Some(PreviousPage), _ => None, diff --git a/src/history.rs b/src/history.rs index 28bfb6f..a45d062 100644 --- a/src/history.rs +++ b/src/history.rs @@ -18,7 +18,7 @@ pub struct HistoryState { } impl NavigatedPage for HistoryState { - fn navigate(&self, message: &HistoryMessage) -> Option { + fn navigate(&mut self, message: &HistoryMessage) -> Option { match message { Back => Some(Page::PreviousPage), } diff --git a/src/import.rs b/src/import.rs index 18f7e57..c2c694b 100644 --- a/src/import.rs +++ b/src/import.rs @@ -62,7 +62,7 @@ pub enum ImportMessage { } impl NavigatedPage for ImportState { - fn navigate(&self, message: &ImportMessage) -> Option { + fn navigate(&mut self, message: &ImportMessage) -> Option { if self.progress.is_some() { return None; } diff --git a/src/lang.rs b/src/lang.rs index 1bdc880..689dc6d 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -1,9 +1,9 @@ -use crate::AppState; use crate::data_provider::card_stats::{delete_stat, load_stats_of_set, update_stat_score}; -use crate::data_provider::history::{HistoryItem, push_note}; +use crate::data_provider::history::{push_note, HistoryItem}; +use crate::AppState; use chrono::{DateTime, Utc}; -use rand::distr::Distribution; use rand::distr::weighted::WeightedIndex; +use rand::distr::Distribution; use rand::prelude::SliceRandom; use rand::rng; use rand::rngs::ThreadRng; @@ -12,7 +12,6 @@ use rayon::iter::IntoParallelRefIterator; use rayon::iter::ParallelIterator; use rhai::{Engine, Scope}; use serde::{Deserialize, Serialize}; -use std::cmp::min; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use std::time::Instant; @@ -300,17 +299,17 @@ pub enum WordOpenMode { } #[derive(Clone)] -pub struct CardSet { +pub struct DeckData { words: Vec, set: Vec, current_word_index: Option, state: Arc>, order_module: OrderModule, - settings: CardSetSettings, + settings: DeckSettings, } -impl CardSet { - pub fn new(settings: &CardSetSettings, state: Arc>) -> Self { +impl DeckData { + pub fn new(settings: &DeckSettings, state: Arc>) -> Self { let state_for = state.clone(); let state_locked = state.lock().unwrap(); @@ -322,31 +321,7 @@ impl CardSet { .cloned() .collect(); let word_ids = last_list.iter().map(|l| l.id).collect::>(); - - // let new_stats: &mut Vec = &mut last_list - // .iter() - // .filter(|word| !saved_ids.contains(&word.id)) - // .map(|word| CardStatistics { - // id: 0, - // word_id: word.id, - // last_open: Utc::now(), - // score: 1, - // set_id: settings.id, - // }) - // .collect(); - // - // let time = Instant::now(); - // - // if !new_stats.is_empty() { - // add_stat_list(new_stats, &state_locked.connection); - // current_set.append(new_stats); - // } - // - // println!( - // "Added {} stats: {}", - // new_stats.len(), - // time.elapsed().as_millis() - // ); + let mut index = 0; for stat in current_set.clone() { if !word_ids.contains(&stat.word_id) { @@ -455,9 +430,10 @@ pub enum OrderMode { FullRandom, } -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Eq, PartialEq, Default)] pub enum AppendMode { Full, + #[default] Manual, } @@ -469,9 +445,9 @@ enum OrderModule { } trait SRSModule { - fn next(&mut self, set: &mut CardSet) -> usize; + fn next(&mut self, set: &mut DeckData) -> usize; fn open(&mut self, status: WordOpenMode, index: usize, updated_word: CardStatistics); - fn init(&mut self, set: &mut CardSet); + fn init(&mut self, set: &mut DeckData); } #[derive(Clone)] @@ -490,7 +466,7 @@ impl RandomSRSModule { } impl SRSModule for RandomSRSModule { - fn next(&mut self, set: &mut CardSet) -> usize { + fn next(&mut self, set: &mut DeckData) -> usize { if self.basket.is_empty() { self.basket = (0..set.words.len()).collect::>(); self.basket.shuffle(&mut rand::rng()) @@ -501,7 +477,7 @@ impl SRSModule for RandomSRSModule { fn open(&mut self, _: WordOpenMode, _: usize, _: CardStatistics) {} - fn init(&mut self, set: &mut CardSet) { + fn init(&mut self, set: &mut DeckData) { self.initialized = true; self.basket = (0..set.words.len()).collect::>(); self.basket.shuffle(&mut rand::rng()) @@ -528,7 +504,7 @@ impl SemiRandomSRSModule { } impl SRSModule for SemiRandomSRSModule { - fn next(&mut self, set: &mut CardSet) -> usize { + fn next(&mut self, set: &mut DeckData) -> usize { let index = self.last_weights.sample(&mut self.generator); if self.history.contains(&index) { @@ -550,7 +526,7 @@ impl SRSModule for SemiRandomSRSModule { .unwrap(); } - fn init(&mut self, set: &mut CardSet) { + fn init(&mut self, set: &mut DeckData) { self.initialized = true; let weights = set .set @@ -562,11 +538,8 @@ impl SRSModule for SemiRandomSRSModule { } impl SemiRandomSRSModule { - fn history_len(&self, set: &CardSet) -> usize { - min( - MAX_HISTORY_LEN, - (set.len() as f32 * MAX_HISTORY_LEN_PART) as usize, - ) + fn history_len(&self, set: &DeckData) -> usize { + ((set.len() as f32 * MAX_HISTORY_LEN_PART) as usize).clamp(1, MAX_HISTORY_LEN) } } @@ -581,7 +554,7 @@ struct WorstWordsSRSModule { } impl SRSModule for WorstWordsSRSModule { - fn next(&mut self, set: &mut CardSet) -> usize { + fn next(&mut self, set: &mut DeckData) -> usize { if self.rounds_remaining == 0 { self.fill_pool(set); self.rounds_remaining = self.rounds_count; @@ -597,7 +570,7 @@ impl SRSModule for WorstWordsSRSModule { fn open(&mut self, _: WordOpenMode, _: usize, _: CardStatistics) {} - fn init(&mut self, _: &mut CardSet) { + fn init(&mut self, _: &mut DeckData) { self.initialized = true; } } @@ -614,7 +587,7 @@ impl WorstWordsSRSModule { } } - fn fill_pool(&mut self, set: &CardSet) { + fn fill_pool(&mut self, set: &DeckData) { let mut sorted = set .set .clone() @@ -632,7 +605,7 @@ impl WorstWordsSRSModule { } #[derive(Clone)] -pub struct CardSetSettings { +pub struct DeckSettings { pub id: u32, pub name: String, pub forward: String, @@ -641,12 +614,11 @@ pub struct CardSetSettings { pub count: Option, pub worst_words_list: Option>, pub open_mode: OrderMode, - pub append_mode: AppendMode, } -impl CardSetSettings { - pub(crate) fn with_name(name: String) -> CardSetSettings { - CardSetSettings { +impl DeckSettings { + pub(crate) fn with_name(name: String) -> DeckSettings { + DeckSettings { id: 0, name, forward: "".to_string(), @@ -655,7 +627,6 @@ impl CardSetSettings { count: None, worst_words_list: None, open_mode: OrderMode::Default, - append_mode: AppendMode::Manual, } } diff --git a/src/main.rs b/src/main.rs index 8cf0b6e..12281c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ use crate::data_provider::card_sets::load_sets; use crate::data_provider::settings::get_setting; use crate::data_provider::sqlite::default_connection; use crate::data_provider::words::{load_word_groups, load_words}; -use crate::lang::{CardSetSettings, WordData, WordGroup}; +use crate::lang::{DeckSettings, WordData, WordGroup}; use crate::navigation::{AppSettings, RootMessage, ScreenState}; use crate::quiz::*; use chrono::NaiveDate; @@ -81,7 +81,7 @@ fn subscription(_state: &ScreenState) -> Subscription { pub struct AppState { pub dictionary: Vec, - pub card_sets: Vec, + pub card_sets: Vec, pub word_groups: Vec, pub connection: Connection, pub sync_data: AppSettings, diff --git a/src/navigation.rs b/src/navigation.rs index 5cb84fd..f8bbbed 100644 --- a/src/navigation.rs +++ b/src/navigation.rs @@ -330,7 +330,7 @@ macro_rules! state_navigate_handle { } pub trait NavigatedPage { - fn navigate(&self, message: &T) -> Option; + fn navigate(&mut self, message: &T) -> Option; fn navigated(&mut self); fn update(&mut self, message: T) -> Task; fn view(&self) -> Element<'_, T>; diff --git a/src/quiz.rs b/src/quiz.rs index d8c62d0..423a629 100644 --- a/src/quiz.rs +++ b/src/quiz.rs @@ -20,7 +20,7 @@ pub struct QuizState { } impl NavigatedPage for QuizState { - fn navigate(&self, message: &QuizMessage) -> Option { + fn navigate(&mut self, message: &QuizMessage) -> Option { if let Back = message { Some(PreviousPage) } else { diff --git a/src/randomizer.rs b/src/randomizer.rs index bce52a9..7c3f684 100644 --- a/src/randomizer.rs +++ b/src/randomizer.rs @@ -20,7 +20,7 @@ pub enum RandomizerMessage { } impl NavigatedPage for RandomizerState { - fn navigate(&self, message: &RandomizerMessage) -> Option { + fn navigate(&mut self, message: &RandomizerMessage) -> Option { if let Back = message { return Some(Page::PreviousPage); } diff --git a/src/repetition.rs b/src/repetition.rs index 1b6e283..7985083 100644 --- a/src/repetition.rs +++ b/src/repetition.rs @@ -1,5 +1,5 @@ use crate::data_provider::voice::get_voice; -use crate::lang::{CardSet, CardSetSettings, CardStatistics, WordData, WordOpenMode}; +use crate::lang::{DeckData, DeckSettings, CardStatistics, WordData, WordOpenMode}; use crate::navigation::Page::PreviousPage; use crate::navigation::{KeyPressedPage, NavigatedPage, Page}; use crate::styling::*; @@ -17,8 +17,8 @@ use tokio::task::spawn_blocking; pub struct RepetitionState { state: Arc>, - pub settings: CardSetSettings, - pub set: CardSet, + pub settings: DeckSettings, + pub set: DeckData, current_word: WordData, current_statistic: CardStatistics, open: bool, @@ -28,7 +28,7 @@ pub struct RepetitionState { } impl NavigatedPage for RepetitionState { - fn navigate(&self, message: &RepetitionMessage) -> Option { + fn navigate(&mut self, message: &RepetitionMessage) -> Option { if let RepetitionMessage::Back = message { Some(PreviousPage) } else { @@ -95,8 +95,8 @@ impl NavigatedPage for RepetitionState { } impl RepetitionState { - pub(crate) fn new(set: CardSetSettings, state: Arc>) -> RepetitionState { - let mut card_set = CardSet::new(&set, state.clone()); + pub(crate) fn new(set: DeckSettings, state: Arc>) -> RepetitionState { + let mut card_set = DeckData::new(&set, state.clone()); let (word, stat) = card_set.next(); let sink_handle = rodio::DeviceSinkBuilder::open_default_sink().unwrap(); diff --git a/src/repetition_settings.rs b/src/repetition_settings.rs index 02169ec..de80607 100644 --- a/src/repetition_settings.rs +++ b/src/repetition_settings.rs @@ -1,6 +1,6 @@ use crate::AppState; use crate::data_provider::card_sets::{delete_set, update_card_set}; -use crate::lang::CardSetSettings; +use crate::lang::DeckSettings; use crate::navigation::Page::PreviousPage; use crate::navigation::{NavigatedPage, Page, RootMessage}; use crate::repetition_settings::RepetitionSettingsMessage::*; @@ -14,7 +14,7 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; pub struct RepetitionSettingsState { - set: CardSetSettings, + set: DeckSettings, index: usize, state: Arc>, real_delete: bool, @@ -37,7 +37,7 @@ impl RepetitionSettingsState { } impl NavigatedPage for RepetitionSettingsState { - fn navigate(&self, message: &RepetitionSettingsMessage) -> Option { + fn navigate(&mut self, message: &RepetitionSettingsMessage) -> Option { if let Back = message { Some(PreviousPage) } else { @@ -149,7 +149,7 @@ impl NavigatedPage for RepetitionSettingsState { } impl RepetitionSettingsState { - fn count_view(&self, set: &CardSetSettings) -> Element<'_, RepetitionSettingsMessage> { + fn count_view(&self, set: &DeckSettings) -> Element<'_, RepetitionSettingsMessage> { if let Some(count) = set.count { return text!("Количество слов: {}", count).into(); } diff --git a/src/repetitions.rs b/src/repetitions.rs index dc1d496..e2095fb 100644 --- a/src/repetitions.rs +++ b/src/repetitions.rs @@ -1,7 +1,8 @@ +use std::ops::Deref; use crate::data_provider::card_sets::{delete_set, update_card_set}; use crate::data_provider::card_stats::{add_stat_list, load_stats_of_set}; use crate::history::HistoryState; -use crate::lang::{AppendMode, CardSetSettings, CardStatistics, OrderMode}; +use crate::lang::{AppendMode, DeckSettings, CardStatistics, OrderMode}; use crate::navigation::Page::{History, PreviousPage, Repetition, RepetitionSettings}; use crate::navigation::{NavigatedPage, Page}; use crate::repetition::RepetitionState; @@ -11,53 +12,65 @@ use crate::styling::*; use crate::{AppState, RootMessage}; use chrono::{Days, Local, Utc}; use hashbrown::{HashMap, HashSet}; -use iced::widget::button::{danger, Status}; pub use iced::widget::button::{Catalog, Style}; +use iced::widget::button::{Status, danger}; use iced::widget::tooltip::Position::Top; use iced::widget::{ - button, column, container, lazy, radio, row, scrollable, space, svg, text, text_input, tooltip, - Column, Row, + Column, Row, button, column, container, lazy, radio, row, scrollable, space, svg, text, + text_input, tooltip, }; use iced::{Background, Border, Center, Color, Element, Fill, Length, Shadow, Task, Theme}; +use iced_core::Padding; use iced_core::border::Radius; use iced_core::svg::Handle; -use iced_core::Padding; use std::sync::{Arc, Mutex}; #[derive(Clone)] pub struct RepetitionsState { - selected_set: Option, + selected_set_index: Option, correct_filters: Vec, current_sets_cards_cache: HashMap, Vec)>, word_id_index_map: HashMap, + local_settings: HashMap, + view_data: Option, pub state: Arc>, + set_names: Vec } impl NavigatedPage for RepetitionsState { - fn navigate(&self, message: &RepetitionsMessage) -> Option { + fn navigate(&mut self, message: &RepetitionsMessage) -> Option { if let Back = message { Some(PreviousPage) } else if let GoToHistory = message { let card_set; { - card_set = self.state.lock().unwrap().card_sets[self.selected_set.unwrap()].id; + card_set = self.state.lock().unwrap().card_sets[self.selected_set_index.unwrap()].id; } Some(History(HistoryState::new(card_set, self.state.clone()))) } else if let GoToRepetition = message { let clone = self.state.clone(); let card_set; { - card_set = self.state.lock().unwrap().card_sets[self.selected_set.unwrap()].clone(); + card_set = self.state.lock().unwrap().card_sets[self.selected_set_index.unwrap()].clone(); } - if card_set.append_mode == AppendMode::Full { + if self.local_settings[&card_set.id].append_mode == AppendMode::Full { self.append_all_words(&card_set); + } else { + let cache = self + .current_sets_cards_cache + .get(&self.selected_set_index.unwrap()) + .unwrap(); + if cache.1.is_empty() || cache.0.is_empty() { + let local_settings = self.local_settings.get_mut(&card_set.id).unwrap(); + local_settings.append_warning = true; + } } Some(Repetition(RepetitionState::new(card_set, clone))) } else if let GoToSettings = message { Some(RepetitionSettings(RepetitionSettingsState::new( - self.selected_set.unwrap(), + self.selected_set_index.unwrap(), self.state.clone(), ))) } else { @@ -65,110 +78,29 @@ impl NavigatedPage for RepetitionsState { } } fn navigated(&mut self) { - self.selected_set = None; + self.clear_selection(); self.current_sets_cards_cache.clear(); } fn update(&mut self, message: RepetitionsMessage) -> Task { - let mut state = self.state.lock().unwrap(); match message { Next => {} Back => {} GoToRepetition => {} GoToHistory => {} GoToSettings => {} - CreateSet => { - let index = state.card_sets.len() + 1; - state - .card_sets - .push(CardSetSettings::with_name(format!("Card set #{}", index))); - self.correct_filters.push(true); - } - DeleteSet => { - let set = state.card_sets.remove(self.selected_set.unwrap()); - self.correct_filters.remove(self.selected_set.unwrap()); - self.selected_set = None; - delete_set(&set, &state.connection); - } - SelectSet(index) => { - self.selected_set = Some(index); - let set = state.card_sets.get(index).unwrap().clone(); - if !self.current_sets_cards_cache.contains_key(&index) { - let added: Vec<_> = load_stats_of_set(&set, &state.connection) - .iter() - .map(|c| self.word_id_index_map[&c.word_id]) - .collect(); - let total = set.get_word_list(&state); - self.current_sets_cards_cache.insert(index, (added, total)); - - } - state.card_sets[index] = set; - } - SetName(new) => { - state.card_sets[self.selected_set.unwrap()].name = new; - } - Save => { - for i in 0..state.card_sets.len() { - self.correct_filters[i] = state.card_sets[i].check_filter(); - } - - let set = &mut state.card_sets[self.selected_set.unwrap()].clone(); - - update_card_set(set, &state.connection); - - state.card_sets[self.selected_set.unwrap()] = set.clone(); - } - SetForward(new) => { - state.card_sets[self.selected_set.unwrap()].forward = new; - } - SetBackward(new) => { - state.card_sets[self.selected_set.unwrap()].backward = new; - } - SetFilter(new) => { - state.card_sets[self.selected_set.unwrap()].filter = new; - } - TryFilter => { - let set = state.card_sets.get(self.selected_set.unwrap()).unwrap(); - let count = set.get_word_list(&state).len(); - state.card_sets[self.selected_set.unwrap()].count = Some(count); - } - SetOpenMode(mode) => { - state - .card_sets - .get_mut(self.selected_set.unwrap()) - .unwrap() - .open_mode = mode; - } - SetAppendMode(mode) => { - let set = state.card_sets.get_mut(self.selected_set.unwrap()).unwrap(); - set.append_mode = mode; - } - AppendWords(count) => { - let adding: Vec; - let set = state.card_sets.get(self.selected_set.unwrap()).unwrap(); - let index = self.selected_set.unwrap(); - { - let total_cache = &mut self.current_sets_cards_cache; - let cache = total_cache.get_mut(&index).unwrap().clone(); - let mut created_set = HashSet::with_capacity(cache.0.len()); - cache.0.iter().for_each(|c| { - created_set.insert(c); - }); - adding = cache - .1 - .iter() - .filter(|c| !created_set.contains(c)) - .take(count) - .cloned() - .collect(); - - let mut new_current = cache.0.clone(); - new_current.append(&mut adding.clone()); - total_cache.insert(index, (new_current, cache.1.clone())); - } - - Self::append_words(&state, set, adding.into_iter()); - } + CreateSet => {} + DeleteSet => {} + SetName(_) => {} + SelectSet(_) => {} + Save => {} + SetForward(_) => {} + SetBackward(_) => {} + SetFilter(_) => {} + TryFilter => {} + SetOpenMode(_) => {} + SetAppendMode(_) => {} + AppendWords(_) => {} } Task::none() } @@ -203,55 +135,34 @@ impl RepetitionsState { let count = state_.card_sets.len(); let mut map = HashMap::with_capacity(state_.dictionary.len()); - state_.dictionary.iter().enumerate().for_each(|(index, word)| {map.insert(word.id, index);}); + state_ + .dictionary + .iter() + .enumerate() + .for_each(|(index, word)| { + map.insert(word.id, index); + }); + let mut local_settings = HashMap::with_capacity(state_.card_sets.len()); + state_.card_sets.iter().for_each(|card_set| { + local_settings.insert(card_set.id, Default::default()); + }); drop(state_); RepetitionsState { - selected_set: None, + selected_set_index: None, correct_filters: vec![true; count], current_sets_cards_cache: Default::default(), word_id_index_map: map, + local_settings, + view_data: None, state, + set_names: vec![], } } } impl RepetitionsState { - fn append_all_words(&self, set: &CardSetSettings) { - let index = self.selected_set.unwrap(); - let cache = &self.current_sets_cards_cache[&index]; - let mut created_set = HashSet::with_capacity(cache.0.len()); - cache.0.iter().for_each(|c| { - created_set.insert(c); - }); - let required = cache - .1 - .iter() - .filter(|i| !created_set.contains(i)).cloned(); - Self::append_words(&self.state.lock().unwrap(), set, required); - } - - fn append_words(state: &AppState, set: &CardSetSettings, indices: impl Iterator) { - let words = &state.dictionary; - let stats = &mut indices - .map(|i| { - let word = words.get(i).unwrap(); - CardStatistics { - id: 0, - word_id: word.id, - last_open: Utc::now(), - score: 1, - set_id: set.id, - } - }) - .collect::>(); - - if !stats.is_empty() { - add_stat_list(stats, &state.connection); - } - } - - fn launch_delete_button(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { + fn launch_delete_button(&self, set: &DeckSettings) -> Element<'_, RepetitionsMessage> { if set.id != 0 { return row![ space().width(Fill), @@ -263,17 +174,8 @@ impl RepetitionsState { } button("Удалить").style(danger).on_press(DeleteSet).into() } - fn selected_set_view(&self) -> Element<'_, RepetitionsMessage> { - if let Some(index) = self.selected_set { - let set; - { - let state = self.state.lock().unwrap(); - if state.card_sets.len() <= index { - return space().width(Length::FillPortion(3)).into(); - } - set = state.card_sets[index].clone(); - } + if let Some(set) = &self.view_data { return column![ scrollable( column![ @@ -362,14 +264,13 @@ impl RepetitionsState { } space().width(Length::FillPortion(2)).into() } - - fn filled_set_data_view(&self, set: &CardSetSettings) -> Column<'_, RepetitionsMessage> { + fn filled_set_data_view(&self, set: &DeckSettings) -> Column<'_, RepetitionsMessage> { column![self.activity_bar(set), self.count_comparator_view()] .align_x(Center) .width(Fill) .spacing(DEFAULT_SPACING) } - fn activity_bar(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { + fn activity_bar(&self, set: &DeckSettings) -> Element<'_, RepetitionsMessage> { const MAX_DAY_COUNT: f32 = 128.0; let state = self.state.lock().unwrap(); @@ -446,21 +347,20 @@ impl RepetitionsState { }) .into() } - - fn word_append_panel(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { + fn word_append_panel(&self, set: &DeckSettings) -> Element<'_, RepetitionsMessage> { column![ text!("Режим добавления карточек"), row![ radio( "Добавлять все доступные", AppendMode::Full, - Some(set.append_mode), + Some(self.local_settings[&set.id].append_mode), SetAppendMode ), radio( "Добавлять вручную", AppendMode::Manual, - Some(set.append_mode), + Some(self.local_settings[&set.id].append_mode), SetAppendMode ) ] @@ -470,9 +370,8 @@ impl RepetitionsState { .spacing(HALF_SPACING) .into() } - - fn adder_panel(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { - match set.append_mode { + fn adder_panel(&self, set: &DeckSettings) -> Element<'_, RepetitionsMessage> { + match self.local_settings[&set.id].append_mode { AppendMode::Full => space().into(), AppendMode::Manual => row![ button("+5").on_press(AppendWords(5)), @@ -484,27 +383,24 @@ impl RepetitionsState { .into(), } } - fn count_comparator_view(&self) -> Element<'_, RepetitionsMessage> { - let cache = &self.current_sets_cards_cache[&self.selected_set.unwrap()]; + let cache = &self.current_sets_cards_cache[&self.selected_set_index.unwrap()]; let now = cache.0.len(); let available = cache.1.len(); text!("{} слова добавлено из {}", now, available).into() } - fn count_view(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { + fn count_view(&self, set: &DeckSettings) -> Element<'_, RepetitionsMessage> { if let Some(count) = set.count { return text!("Количество слов: {}", count).into(); } space().into() } - fn sets_list(&self) -> Column<'_, RepetitionsMessage> { let mut column = Column::new(); - let sets = &self.state.lock().unwrap().card_sets; - for (i, set) in sets.iter().enumerate() { + for (i, set) in self.set_names.iter().enumerate() { column = column.push( - button(text!("{}", set.name.clone())) + button(text!("{}", set.clone())) .on_press_with(move || SelectSet(i)) .style(move |_x: &Theme, status: Status| Style { background: if status == Status::Hovered { @@ -532,6 +428,48 @@ impl RepetitionsState { } } +impl RepetitionsState { + fn append_all_words(&self, set: &DeckSettings) { + let index = self.selected_set_index.unwrap(); + let cache = &self.current_sets_cards_cache[&index]; + let mut created_set = HashSet::with_capacity(cache.0.len()); + cache.0.iter().for_each(|c| { + created_set.insert(c); + }); + let required = cache.1.iter().filter(|i| !created_set.contains(i)).cloned(); + Self::append_words(&self.state.lock().unwrap(), set, required); + } + fn append_words(state: &AppState, set: &DeckSettings, indices: impl Iterator) { + let words = &state.dictionary; + let stats = &mut indices + .map(|i| { + let word = words.get(i).unwrap(); + CardStatistics { + id: 0, + word_id: word.id, + last_open: Utc::now(), + score: 1, + set_id: set.id, + } + }) + .collect::>(); + + if !stats.is_empty() { + add_stat_list(stats, &state.connection); + } + } + fn select_set(&mut self, index: usize) { + let state = self.state.lock().unwrap(); + if let Some(set) = state.card_sets.get(index) { + self.selected_set_index = Some(index); + + } + } + + fn clear_selection(&mut self) { + self.selected_set_index = None; + } +} #[derive(Clone)] pub enum RepetitionsMessage { Next, @@ -552,3 +490,24 @@ pub enum RepetitionsMessage { GoToSettings, AppendWords(usize), } + +#[derive(Clone, Default)] +struct DeckLocalSetting { + append_mode: AppendMode, + append_warning: bool, +} + +#[derive(Clone)] +struct SetViewData{ + set_local_settings: DeckLocalSetting, + set_settings: DeckSettings, + existing_words_indices: Vec, + available_words_indices: Vec, +} +impl Deref for SetViewData { + type Target = DeckSettings; + + fn deref(&self) -> &Self::Target { + &self.set_settings + } +} \ No newline at end of file diff --git a/src/selector.rs b/src/selector.rs index 7faced7..8eae3db 100644 --- a/src/selector.rs +++ b/src/selector.rs @@ -36,7 +36,7 @@ pub enum SelectorMessage { } impl NavigatedPage for SelectorState { - fn navigate(&self, message: &SelectorMessage) -> Option { + fn navigate(&mut self, message: &SelectorMessage) -> Option { if let SelectorMessage::Goto = message { return if self.is_writing { let writing = WritingState::new(&self.set); diff --git a/src/sync.rs b/src/sync.rs index c45c6b9..a273fce 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -37,7 +37,7 @@ pub struct SyncState { } impl NavigatedPage for SyncState { - fn navigate(&self, message: &SyncMessage) -> Option { + fn navigate(&mut self, message: &SyncMessage) -> Option { if let Back = message && !self.frozen { diff --git a/src/word.rs b/src/word.rs index c8f8301..84cc90e 100644 --- a/src/word.rs +++ b/src/word.rs @@ -18,7 +18,7 @@ pub struct WordState { } impl NavigatedPage for WordState { - fn navigate(&self, message: &WordMessage) -> Option { + fn navigate(&mut self, message: &WordMessage) -> Option { if let Back = message { Some(PreviousPage) } else { diff --git a/src/writing.rs b/src/writing.rs index 409415d..d5a4228 100644 --- a/src/writing.rs +++ b/src/writing.rs @@ -19,7 +19,7 @@ pub struct WritingState { } impl NavigatedPage for WritingState { - fn navigate(&self, message: &WritingMessage) -> Option { + fn navigate(&mut self, message: &WritingMessage) -> Option { if let WritingMessage::Back = message { Some(PreviousPage) } else {