Data provider refactor #11

Merged
micialware merged 11 commits from data-provider-refactor into master 2026-08-25 12:21:54 +03:00
4 changed files with 41 additions and 56 deletions
Showing only changes of commit dddac01bdf - Show all commits

No files matched your search

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