diff --git a/src/core/deck.rs b/src/core/deck.rs index 03e0c76..cffec4b 100644 --- a/src/core/deck.rs +++ b/src/core/deck.rs @@ -58,30 +58,24 @@ impl DeckData { } pub fn next(&mut self) -> (WordData, CardStatistics) { - let index = match self.order_module.clone() { - OrderModule::SemiRandomSRS(mut module) => { + let index = match self.order_module { + OrderModule::SemiRandomSRS(ref mut module) => { if !module.initialized { - module.init(self) + module.init(self.set.as_slice()) } - let index = module.next(self); - self.order_module = OrderModule::SemiRandomSRS(module); - index + module.next(self.set.as_slice()) } - OrderModule::RandomSRS(mut module) => { + OrderModule::RandomSRS(ref mut module) => { if !module.initialized { - module.init(self) + module.init(self.set.as_slice()) } - let index = module.next(self); - self.order_module = OrderModule::RandomSRS(module); - index + module.next(self.set.as_slice()) } - OrderModule::WorstWordsSRS(mut module) => { + OrderModule::WorstWordsSRS(ref mut module) => { if !module.initialized { - module.init(self) + module.init(self.set.as_slice()) } - let index = module.next(self); - self.order_module = OrderModule::WorstWordsSRS(module); - index + module.next(self.set.as_slice()) } }; diff --git a/src/core/srs.rs b/src/core/srs.rs index 0099890..b6c0d5a 100644 --- a/src/core/srs.rs +++ b/src/core/srs.rs @@ -1,9 +1,8 @@ -use crate::core::deck::DeckData; +use crate::data::entities::CardStatistics; use rand::distr::weighted::WeightedIndex; use rand::prelude::ThreadRng; use rand::prelude::{Distribution, SliceRandom}; use rand::rng; -use crate::data::entities::CardStatistics; const MAX_HISTORY_LEN: usize = 20; const MAX_HISTORY_LEN_PART: f32 = 0.33; @@ -29,9 +28,9 @@ pub enum OrderModule { WorstWordsSRS(WorstWordsSRSModule), } pub trait SRSModule { - fn next(&mut self, set: &mut DeckData) -> usize; + fn next(&mut self, set: &[CardStatistics]) -> usize; fn open(&mut self, status: WordOpenMode, index: usize, updated_word: &CardStatistics); - fn init(&mut self, set: &mut DeckData); + fn init(&mut self, set: &[CardStatistics]); } #[derive(Clone)] pub struct RandomSRSModule { @@ -47,11 +46,11 @@ impl RandomSRSModule { } } impl SRSModule for RandomSRSModule { - fn next(&mut self, set: &mut DeckData) -> usize { + fn next(&mut self, set: &[CardStatistics]) -> usize { match self.basket.pop() { Some(index) => index, None => { - self.basket = (0..set.words.len()).collect::>(); + self.basket = (0..set.len()).collect::>(); self.basket.shuffle(&mut rand::rng()); self.basket.pop().expect("empty basket") } @@ -60,9 +59,9 @@ impl SRSModule for RandomSRSModule { fn open(&mut self, _: WordOpenMode, _: usize, _: &CardStatistics) {} - fn init(&mut self, set: &mut DeckData) { + fn init(&mut self, set: &[CardStatistics]) { self.initialized = true; - self.basket = (0..set.set.len()).collect::>(); + self.basket = (0..set.len()).collect::>(); self.basket.shuffle(&mut rand::rng()) } } @@ -84,7 +83,7 @@ impl SemiRandomSRSModule { } } impl SRSModule for SemiRandomSRSModule { - fn next(&mut self, set: &mut DeckData) -> usize { + fn next(&mut self, set: &[CardStatistics]) -> usize { let index = self.last_weights.sample(&mut self.generator); if self.history.contains(&index) && self.history.len() != 1 { @@ -104,10 +103,9 @@ impl SRSModule for SemiRandomSRSModule { .update_weights(&[(index, &new_weight)]) .expect("update weights error"); } - fn init(&mut self, set: &mut DeckData) { + fn init(&mut self, set: &[CardStatistics]) { self.initialized = true; let weights = set - .set .iter() .map(|s| (100.0 / s.calculated_score()).powf(2.0) * 2.0) .collect::>(); @@ -115,7 +113,7 @@ impl SRSModule for SemiRandomSRSModule { } } impl SemiRandomSRSModule { - fn history_len(&self, set: &DeckData) -> usize { + fn history_len(&self, set: &[CardStatistics]) -> usize { ((set.len() as f32 * MAX_HISTORY_LEN_PART) as usize).clamp(1, MAX_HISTORY_LEN) } } @@ -129,7 +127,7 @@ pub struct WorstWordsSRSModule { rounds_count: u8, } impl SRSModule for WorstWordsSRSModule { - fn next(&mut self, set: &mut DeckData) -> usize { + fn next(&mut self, set: &[CardStatistics]) -> usize { if self.rounds_remaining == 0 { self.fill_pool(set); self.rounds_remaining = self.rounds_count; @@ -147,7 +145,7 @@ impl SRSModule for WorstWordsSRSModule { fn open(&mut self, _: WordOpenMode, _: usize, _: &CardStatistics) {} - fn init(&mut self, _: &mut DeckData) { + fn init(&mut self, _: &[CardStatistics]) { self.initialized = true; } } @@ -162,17 +160,13 @@ impl WorstWordsSRSModule { queue: vec![], } } - fn fill_pool(&mut self, set: &DeckData) { - let mut sorted = set - .set - .clone() - .into_iter() - .zip(0..set.set.len()) + fn fill_pool(&mut self, set: &[CardStatistics]) { + let mut sorted = set.iter().enumerate() .collect::>(); - sorted.sort_by_key(|c| c.0.score); + sorted.sort_by_key(|c| c.1.score); let mut worst = sorted[0..self.pool_size] .iter() - .map(|(_, index)| *index) + .map(|(index, _)| *index) .collect::>(); worst.shuffle(&mut rand::rng()); self.pool = worst; diff --git a/src/data_provider/web_api.rs b/src/data_provider/web_api.rs index b166775..d1d6133 100644 --- a/src/data_provider/web_api.rs +++ b/src/data_provider/web_api.rs @@ -38,8 +38,7 @@ fn compress(data: Vec) -> Result, NotificationData> { let mut encoder = Encoder::new(Vec::new(), DEFAULT_COMPRESSION_LEVEL).map_err(|_| CompressError)?; io::copy(&mut &data[..], &mut encoder).map_err(|_| PermissionDenied)?; - encoder.finish().map_err(|_| CompressError)?; - Ok(data) + encoder.finish().map_err(|_| CompressError) } pub async fn load_data(id: String, temp: bool) -> MaybeError { diff --git a/src/navigation.rs b/src/navigation.rs index 1b3f223..fbe96f5 100644 --- a/src/navigation.rs +++ b/src/navigation.rs @@ -6,11 +6,11 @@ use crate::data_provider::web_api::{ get_local_version, get_web_version, load_data, set_local_version, }; use crate::fs::*; -use crate::{message_navigation, push_error, push_error_task}; use crate::navigation::Page::*; use crate::navigation::RootMessage::{ DataLoaded, Keyboard, Notification, PushNotification, UpdateData, }; +use crate::notification::NotificationData::PermissionDenied; use crate::notification::{ NotificationData, NotificationManager, NotificationMessage, NotificationRequest, }; @@ -30,6 +30,7 @@ use crate::pages::writing::{WritingMessage, WritingState}; use crate::state_navigate_handle; use crate::state_update; use crate::view_navigation; +use crate::{message_navigation, push_error, push_error_task}; use chrono::NaiveDate; use hashbrown::HashMap; use iced::keyboard::Event; @@ -41,7 +42,6 @@ use parking_lot::Mutex; use rusqlite::Connection; use std::sync::Arc; use std::time::Instant; -use crate::notification::NotificationData::PermissionDenied; impl Default for ScreenState { fn default() -> Self { @@ -109,7 +109,8 @@ impl ScreenState { create_db(); info!("Db created"); let state = ScreenState::default(); - let reading_additional_task = Task::perform(Self::load_additional_data(), |data| data); + let reading_additional_task = + Task::perform(Self::load_additional_data(), |data| data.unwrap_or_else(|err| push_error!(err))); let mut final_task = reading_additional_task; let state_guard = state.app_state.lock(); @@ -126,7 +127,7 @@ impl ScreenState { RootMessage::None } } - Err(err) => PushNotification(NotificationRequest::Warning(err)), + Err(err) => push_error!(err), }), ]); } @@ -136,39 +137,36 @@ impl ScreenState { (state, final_task) } - async fn load_additional_data() -> RootMessage { - let directory = history_dir(); + async fn load_additional_data() -> Result { + let directory = history_dir()?; - if let Ok(directory) = directory { - let mut map = HashMap::new(); - for file in directory - .read_dir() - .expect("Cant read history directory") - .flatten() + let mut map = HashMap::new(); + for file in directory + .read_dir() + .map_err(|_| PermissionDenied)? + .filter_map(Result::ok) + { + let mut vec = vec![]; + let history_file_name = match file.file_name().into_string() { + Err(_) => continue, + Ok(v) => v, + }; + + if let Ok(id) = history_file_name.split('_').collect::>()[1].parse::() + && let Ok(history) = get_history_of_set(id) { - let mut vec = vec![]; - let history_file_name = match file.file_name().into_string() { - Err(_) => continue, - Ok(v) => v, - }; - - if let Ok(id) = history_file_name[4..history_file_name.len() - 12].parse::() - && let Ok(history) = get_history_of_set(id) - { - let by_date = history.chunk_by(|x, x1| { - x.timestamp.naive_local().date() == x1.timestamp.naive_local().date() - }); - for group in by_date { - vec.push((group[0].timestamp.naive_local().date(), group.len() as u32)); - } - map.insert(id, vec); - } else { - return PushNotification(NotificationRequest::Warning(PermissionDenied)); + let by_date = history.chunk_by(|x, x1| { + x.timestamp.naive_local().date() == x1.timestamp.naive_local().date() + }); + for group in by_date { + vec.push((group[0].timestamp.naive_local().date(), group.len() as u32)); } + map.insert(id, vec); + } else { + continue; } - return DataLoaded(map); } - PushNotification(NotificationRequest::Warning(directory.err().unwrap())) + Ok(DataLoaded(map)) } async fn load_web_backup(string: String) -> Result { @@ -205,8 +203,8 @@ impl ScreenState { } let db_file = db_path(); let temp_db_file = temp_db_path(); - if std::fs::rename(temp_db_file, &db_file).is_err(){ - return push_error_task!(PermissionDenied) + if std::fs::rename(temp_db_file, &db_file).is_err() { + return push_error_task!(PermissionDenied); } state.connection = default_connection(); @@ -294,11 +292,11 @@ impl ScreenState { } fn handle_keyboard(&mut self, message: Event) -> Task { - if let Some(page) = self.stack.last_mut(){ + if let Some(page) = self.stack.last_mut() { return match page { Repetition(page) => page.press(&message), _ => Task::none(), - } + }; } Task::none() }