use crate::app::AppState; use crate::core::srs::OrderModule::{Fsrs, RandomSRS, SemiRandomSRS, WorstWordsSRS}; use crate::core::srs::{ FsrsModule, OrderMode, OrderModule, RandomSRSModule, SRSModule, SemiRandomSRSModule, WordOpenMode, WorstWordsSRSModule, }; use crate::data::entities::*; use crate::data_provider::card_states::{load_stats_of_deck, update_stat_score}; use crate::data_provider::history::push_note; use crate::notification::{MaybeError, NotificationData}; use chrono::Utc; use parking_lot::Mutex; use std::sync::Arc; #[derive(Clone)] pub struct DeckData { pub(crate) words: Vec, pub(crate) set: Vec, current_word_index: Option, state: Arc>, order_module: OrderModule, open_mode: OrderMode, settings: DeckSettings, } impl DeckData { pub fn new( settings: &DeckSettings, state: Arc>, ) -> Result { let state_for = state.clone(); let state_locked = state.lock(); let stats = load_stats_of_deck(settings, &state_locked.connection)?; let words = stats .iter() .map(|stat| { state_locked .dictionary .binary_search_by_key(&stat.word_id, |w| w.id) .expect("No word found in dictionary") }) .map(|index| &state_locked.dictionary[index]) .cloned() .collect(); Ok(Self { set: stats, words, current_word_index: None, state: state_for, order_module: Fsrs(FsrsModule::new()), open_mode: settings.open_mode, settings: settings.clone(), }) } pub fn next(&mut self) -> (WordData, CardStatistics) { let index = match self.order_module { SemiRandomSRS(ref mut module) => { if !module.initialized { module.init(self.set.as_slice()) } module.next(self.set.as_slice()) } RandomSRS(ref mut module) => { if !module.initialized { module.init(self.set.as_slice()) } module.next(self.set.as_slice()) } WorstWordsSRS(ref mut module) => { if !module.initialized { module.init(self.set.as_slice()) } module.next(self.set.as_slice()) } Fsrs(ref mut module) => { if !module.initialized { module.init(self.set.as_slice()) } module.next(self.set.as_slice()) } }; self.current_word_index = Some(index); (self.words[index].clone(), self.set[index].clone()) } pub fn open(&mut self, status: WordOpenMode) -> MaybeError { if let Some(index) = self.current_word_index { let word: &mut CardStatistics = &mut self.set[index]; let old_score = word.score; word.update(status); let new_score = word.score; match self.order_module { SemiRandomSRS(ref mut module) => { module.open(status, index, word); } RandomSRS(ref mut module) => { module.open(status, index, word); } WorstWordsSRS(ref mut module) => { module.open(status, index, word); } Fsrs(ref mut module) => { module.open(status, index, word); } } if let Fsrs(ref fsrs) = self.order_module && fsrs.finished() { self.order_module = match self.open_mode { OrderMode::Default => SemiRandomSRS(SemiRandomSRSModule::new()), OrderMode::TrainWorstFirst => WorstWordsSRS(WorstWordsSRSModule::new()), OrderMode::FullRandom => RandomSRS(RandomSRSModule::new()), } } update_stat_score(word, &self.state.lock().connection)?; let _ = push_note( self.settings.id, HistoryItem { timestamp: Utc::now(), word_id: word.word_id, mode: status, before: old_score, after: new_score, }, ); } Ok(()) } pub fn len(&self) -> usize { self.set.len() } }