Sync solved

This commit is contained in:
micialware committed 2026-09-06 23:55:50 +03:00
1 parent 22c05250aa
commit 1afb7493f6
9 files changed
+164 -158

No files matched your search

+1 -1
View File
@@ -5,7 +5,7 @@ create table states
word_id INTEGER not null word_id INTEGER not null
references words references words
on delete cascade, on delete cascade,
set_id INTEGER not null deck_id INTEGER not null
references decks references decks
on delete cascade, on delete cascade,
score INTEGER default 1 not null, score INTEGER default 1 not null,
+9 -10
View File
@@ -1,8 +1,11 @@
use std::sync::Arc; use crate::data::repositories::Repository;
use crate::data_provider::decks::{DeckRepository}; use crate::data_provider::card_states::CardStateRepository;
use crate::data_provider::decks::DeckRepository;
use crate::data_provider::history::HistoryRepository;
use crate::data_provider::settings::get_setting; use crate::data_provider::settings::get_setting;
use crate::data_provider::sqlite::{SqliteConnection}; use crate::data_provider::sqlite::SqliteConnection;
use crate::data_provider::words::{WordRepository}; use crate::data_provider::word_groups::WordGroupRepository;
use crate::data_provider::words::WordRepository;
use crate::navigation::RootMessage::Keyboard; use crate::navigation::RootMessage::Keyboard;
use crate::navigation::{AppSettings, RootMessage, ScreenState}; use crate::navigation::{AppSettings, RootMessage, ScreenState};
use iced::{Subscription, keyboard, window}; use iced::{Subscription, keyboard, window};
@@ -13,10 +16,7 @@ use iced_core::{Font, Size, Theme};
use log::info; use log::info;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use rusqlite::Connection; use rusqlite::Connection;
use crate::data::repositories::Repository; use std::sync::Arc;
use crate::data_provider::card_states::CardStateRepository;
use crate::data_provider::history::HistoryRepository;
use crate::data_provider::word_groups::WordGroupRepository;
pub const USER_FONT: Font = Font::with_name("Noto Sans JP"); pub const USER_FONT: Font = Font::with_name("Noto Sans JP");
@@ -100,10 +100,9 @@ pub fn fill_state(state: &mut AppState) {
let setting = load_settings(&connection); let setting = load_settings(&connection);
state.word_groups.write().start().unwrap(); state.word_groups.write().start().unwrap();
state.dictionary.write().start().unwrap(); state.dictionary.write().start().unwrap();
state.decks.write().start().unwrap(); state.decks.write().start().unwrap();
state.sync_data = Arc::new(RwLock::new(setting)) state.sync_data = Arc::new(RwLock::new(setting))
} }
+4 -4
View File
@@ -164,9 +164,9 @@ impl DeckData {
self.set.len() self.set.len()
} }
pub fn list(deck: &DeckSettings, state: &AppState) -> Result<Vec<EntityHandle<WordData>>, NotificationData> { pub fn list(deck: &DeckSettings, state: &AppState) -> Vec<EntityHandle<WordData>> {
let time = Instant::now(); let time = Instant::now();
let mut list = vec![]; let list = vec![];
let engine = Engine::new(); let engine = Engine::new();
let ast = engine.compile(&deck.filter); let ast = engine.compile(&deck.filter);
@@ -201,9 +201,9 @@ impl DeckData {
info!("Collecting available words is {:?}", time.elapsed()); info!("Collecting available words is {:?}", time.elapsed());
let handles =query.handles().collect(); let handles =query.handles().collect();
drop(query); drop(query);
Ok(handles) handles
} else { } else {
Ok(list) list
} }
} }
} }
+6 -1
View File
@@ -126,7 +126,7 @@ impl DeckSettings {
pub struct CardState { pub struct CardState {
pub id: Id, pub id: Id,
pub word_id: Id, pub word_id: Id,
pub set_id: Id, pub deck_id: Id,
pub last_open: DateTime<Utc>, pub last_open: DateTime<Utc>,
pub score: u8, pub score: u8,
pub fsrs_opened: NaiveDate, pub fsrs_opened: NaiveDate,
@@ -200,6 +200,11 @@ impl<T> EntityHandle<T> {
_phantom: Default::default(), _phantom: Default::default(),
} }
} }
pub fn from_id(id: Id) -> Self {
Self::new(id, id.0 as usize, false)
}
pub fn index(&self) -> usize { pub fn index(&self) -> usize {
(self.index << 1 >> 1) as usize (self.index << 1 >> 1) as usize
} }
+6 -6
View File
@@ -15,7 +15,7 @@ pub type CardStateRepositoryInner = DataRepositoryInner<CardState, SqliteDbLayer
pub struct CardStatesQuerySet; pub struct CardStatesQuerySet;
impl TableAccessQuerySet<CardState> for CardStatesQuerySet { impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
fn load() -> &'static str { fn load() -> &'static str {
"SELECT id, word_id, set_id, score, last_opened, fsrs_opened, fsrs_memory, fsrs_open_day FROM states" "SELECT id, word_id, deck_id, score, last_opened, fsrs_opened, fsrs_memory, fsrs_open_day FROM states"
} }
fn save() -> &'static str { fn save() -> &'static str {
@@ -23,7 +23,7 @@ impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
} }
fn add() -> &'static str { fn add() -> &'static str {
"INSERT INTO states (word_id, set_id, score, last_opened, fsrs_opened, fsrs_memory, fsrs_open_day) VALUES (?1, ?2, ?3, ?4)" "INSERT INTO states (word_id, deck_id, score, last_opened, fsrs_opened, fsrs_memory, fsrs_open_day) VALUES (?1, ?2, ?3, ?4)"
} }
fn name() -> &'static str { fn name() -> &'static str {
@@ -34,7 +34,7 @@ impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
Ok(CardState { Ok(CardState {
id: row.get(0)?, id: row.get(0)?,
word_id: row.get(1)?, word_id: row.get(1)?,
set_id: row.get(2)?, deck_id: row.get(2)?,
score: row.get(3)?, score: row.get(3)?,
fsrs_opened: NaiveDate::from_epoch_days(row.get::<usize, i32>(5)?) fsrs_opened: NaiveDate::from_epoch_days(row.get::<usize, i32>(5)?)
.expect("Incorrect date encoding"), .expect("Incorrect date encoding"),
@@ -48,7 +48,7 @@ impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
fn insert_params(entity: &CardState) -> impl Params { fn insert_params(entity: &CardState) -> impl Params {
( (
entity.word_id, entity.word_id,
entity.set_id, entity.deck_id,
entity.score, entity.score,
entity.last_open.timestamp(), entity.last_open.timestamp(),
entity.fsrs_opened.to_epoch_days(), entity.fsrs_opened.to_epoch_days(),
@@ -73,7 +73,7 @@ pub fn load_stats_of_deck(
Ok(CardState { Ok(CardState {
id: row.get(0)?, id: row.get(0)?,
word_id: row.get(1)?, word_id: row.get(1)?,
set_id: set.id, deck_id: set.id,
score: row.get(2)?, score: row.get(2)?,
fsrs_opened: NaiveDate::from_epoch_days(row.get::<usize, i32>(4)?) fsrs_opened: NaiveDate::from_epoch_days(row.get::<usize, i32>(4)?)
.expect("Incorrect date encoding"), .expect("Incorrect date encoding"),
@@ -126,7 +126,7 @@ pub fn add_stat_list(stats: &mut [CardState], connection: &mut Connection) -> Ma
for stat in stats.iter() { for stat in stats.iter() {
stmt.execute(params![ stmt.execute(params![
stat.word_id, stat.word_id,
stat.set_id, stat.deck_id,
stat.score, stat.score,
stat.last_open.timestamp(), stat.last_open.timestamp(),
stat.fsrs_opened.to_epoch_days(), stat.fsrs_opened.to_epoch_days(),
+3
View File
@@ -110,4 +110,7 @@ impl SqliteConnection {
pub fn finish(&mut self) { pub fn finish(&mut self) {
self.0 = None; self.0 = None;
} }
pub fn restart(&mut self) {
self.0 = Some(default_connection());
}
} }
+6 -8
View File
@@ -86,12 +86,10 @@ impl NavigatedPage<RepetitionSettingsMessage> for RepetitionSettingsState {
self.correct_filter = self.settings_data.check_filter(); self.correct_filter = self.settings_data.check_filter();
self.filter_changed = true; self.filter_changed = true;
} }
TryFilter => match DeckData::list(&self.settings_data, &self.state) { TryFilter => {
Ok(list) => { let list = DeckData::list(&self.settings_data, &self.state);
self.filtered_words = Some(list.len() as u32); self.filtered_words = Some(list.len() as u32);
} }
Err(err) => return push_error_task!(err),
},
DeleteSet => { DeleteSet => {
if !self.real_delete { if !self.real_delete {
self.real_delete = true; self.real_delete = true;
@@ -183,10 +181,10 @@ fn update_deck_stats(deck: &DeckSettings, state: &AppState) -> MaybeError {
let states_repo = &mut state.card_states.write(); let states_repo = &mut state.card_states.write();
let deck_id = deck.id; let deck_id = deck.id;
let mut db_stats = states_repo let mut db_stats = states_repo
.query_par(Arc::new(move |s| s.set_id == deck_id)) .query_par(Arc::new(move |s| s.deck_id == deck_id))
.iter(&states_repo) .iter(&states_repo)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let filtered_words = DeckData::list(deck, state)? let filtered_words = DeckData::list(deck, state)
.iter() .iter()
.map(|w| w.id) .map(|w| w.id)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
+82 -95
View File
@@ -1,8 +1,9 @@
use crate::app::AppState; use crate::app::AppState;
use crate::core::deck::DeckData;
use crate::core::srs::{AppendMode, OrderMode}; use crate::core::srs::{AppendMode, OrderMode};
use crate::data::Id; use crate::data::entities::{CardState, DeckSettings, EntityHandle, WordData};
use crate::data::entities::{CardState, DeckSettings}; use crate::data::repositories::Repository;
use crate::data_provider::card_states::{add_stat_list, load_stats_of_deck}; use crate::data_provider::card_states::add_stat_list;
use crate::navigation::Page::{History, PreviousPage, Repetition, RepetitionSettings}; use crate::navigation::Page::{History, PreviousPage, Repetition, RepetitionSettings};
use crate::navigation::{NavigatedPage, Page, RootMessage}; use crate::navigation::{NavigatedPage, Page, RootMessage};
use crate::notification::{MaybeError, NotificationRequest}; use crate::notification::{MaybeError, NotificationRequest};
@@ -14,7 +15,7 @@ use crate::push_error;
use crate::push_error_task; use crate::push_error_task;
use crate::styling::*; use crate::styling::*;
use chrono::{Days, Local, Utc}; use chrono::{Days, Local, Utc};
use hashbrown::{HashMap, HashSet}; use hashbrown::HashSet;
pub use iced::widget::button::{Catalog, Style}; pub use iced::widget::button::{Catalog, Style};
use iced::widget::button::{Status, danger}; use iced::widget::button::{Status, danger};
use iced::widget::tooltip::Position::Top; use iced::widget::tooltip::Position::Top;
@@ -26,14 +27,12 @@ use iced::{Background, Border, Center, Color, Element, Fill, Length, Shadow, Tas
use iced_core::Padding; use iced_core::Padding;
use iced_core::border::Radius; use iced_core::border::Radius;
use iced_core::svg::Handle; use iced_core::svg::Handle;
use parking_lot::Mutex;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
#[derive(Clone)] #[derive(Clone)]
pub struct RepetitionsState { pub struct RepetitionsState {
word_id_index_map: HashMap<Id, usize>, selected_deck_handle: Option<EntityHandle<DeckSettings>>,
selected_deck_index: Option<usize>,
decks: Vec<DeckViewData>, decks: Vec<DeckViewData>,
state: AppState, state: AppState,
} }
@@ -48,11 +47,10 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
self.state.clone(), self.state.clone(),
))) )))
} else if let GoToRepetition = message { } else if let GoToRepetition = message {
let clone = self.state.clone(); let mut state_clone = self.state.clone();
let selected_set = self.selected_deck_mut().unwrap(); let selected_set = self.selected_deck_mut().unwrap();
if selected_set.append_mode == AppendMode::Full { if selected_set.append_mode == AppendMode::Full {
if let Err(_err) = Self::append_all_words(&mut clone.lock(), selected_set) { if let Err(_err) = Self::append_all_words(&mut state_clone, selected_set) {
return None; return None;
} }
selected_set.existing_words_indices = selected_set.available_words_indices.clone(); selected_set.existing_words_indices = selected_set.available_words_indices.clone();
@@ -65,7 +63,7 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
} }
if let Ok(repetition_state) = if let Ok(repetition_state) =
RepetitionState::new(selected_set.general_settings.clone(), clone) RepetitionState::new(selected_set.general_settings.clone(), self.state.clone())
{ {
return Some(Repetition(repetition_state)); return Some(Repetition(repetition_state));
} }
@@ -73,7 +71,7 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
None None
} else if let GoToSettings = message { } else if let GoToSettings = message {
Some(RepetitionSettings(RepetitionSettingsState::new( Some(RepetitionSettings(RepetitionSettingsState::new(
self.selected_deck().unwrap().index.unwrap(), EntityHandle::from_id(self.selected_deck().unwrap().id),
self.state.clone(), self.state.clone(),
))) )))
} else { } else {
@@ -81,23 +79,20 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
} }
} }
fn navigated(&mut self) { fn navigated(&mut self) {
if let Some(index) = self.selected_deck_index { if let Some(index) = self.selected_deck_handle {
let state = self.state.lock(); let decks = self.state.decks.read();
if let Some(global_deck) = state.decks.get(index) { if let None = decks.get_static(index) {
if global_deck.id != self.selected_deck().unwrap().id { let position = self
drop(state); .decks
self.decks.remove(index); .iter()
self.clear_selection(); .position(|deck_view_data: &DeckViewData| deck_view_data.id == index.id)
} else { .unwrap();
self.decks[index].general_settings = state.decks[index].clone(); self.decks.remove(position);
drop(state); drop(decks);
let _ = self.fill_deck_word_indices(); self.clear_selection();
}
} else {
drop(state);
self.decks.remove(index);
self.clear_selection()
} }
} else {
let _ = self.fill_deck_word_indices();
} }
} }
fn update(&mut self, message: RepetitionsMessage) -> Task<RootMessage> { fn update(&mut self, message: RepetitionsMessage) -> Task<RootMessage> {
@@ -116,25 +111,27 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
available_words_indices: Default::default(), available_words_indices: Default::default(),
indices_ready: false, indices_ready: false,
append_mode: Default::default(), append_mode: Default::default(),
index: None, count: None,
open_mode: OrderMode::Default,
}); });
} }
DeleteSet => { DeleteSet => {
let index = self.selected_deck_index.unwrap(); let index = self.selected_deck_handle.unwrap();
self.clear_selection(); self.clear_selection();
let deck = self.decks.remove(index); let deck = self.decks.remove(
if deck.id.is_valid() { self.decks
let mut state = self.state.lock(); .iter()
state.decks.remove(index); .position(|dvd| dvd.id == index.id)
self.decks = self .unwrap(),
.decks );
.clone() if index.real() {
.into_iter() let mut repo = self.state.decks.write();
.map(|mut deck| { if let Err(err) = repo.delete(index) {
deck.index = state.decks.iter().position(|d| d.id == deck.id); return push_error_task!(err);
deck }
})
.collect(); let index = self.decks.iter().position(|dvd| dvd.id == index.id);
self.decks.remove(index.unwrap());
} }
} }
SetName(value) => { SetName(value) => {
@@ -152,20 +149,19 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
} }
Save => { Save => {
let mut deck = self.selected_deck().unwrap().clone(); let mut deck = self.selected_deck().unwrap().clone();
let mut state = self.state.lock(); let handle = self.selected_deck_handle.unwrap();
{ let mut repo = self.state.decks.write();
if let Err(e) = update_deck(&mut deck.general_settings, &state.connection) {
return Task::done(RootMessage::PushNotification( repo.set_static(handle, *deck);
NotificationRequest::Error(e), if let Err(err) = repo.save(&mut handle.clone()) {
)); return push_error_task!(err);
} }
if let Some(index) = deck.index { if let Some(index) = deck.index {
state.decks[index] = deck.general_settings.clone(); state.decks[index] = deck.general_settings.clone();
} else { } else {
state.decks.push(deck.general_settings.clone()); state.decks.push(deck.general_settings.clone());
deck.index = Some(state.decks.len() - 1); deck.index = Some(state.decks.len() - 1);
self.decks[self.selected_deck_index.unwrap()] = deck.clone(); self.decks[self.selected_deck_handle.unwrap()] = deck.clone();
}
} }
} }
SetForward(value) => { SetForward(value) => {
@@ -181,23 +177,21 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
deck.general_settings.filter = value; deck.general_settings.filter = value;
} }
TryFilter => { TryFilter => {
let state = self.state.lock();
let deck = self.selected_deck().unwrap(); let deck = self.selected_deck().unwrap();
let count = deck.get_word_list(&state).len(); let count = DeckData::list(&deck, &self.state).len();
drop(state);
let deck = self.selected_deck_mut().unwrap(); let deck = self.selected_deck_mut().unwrap();
deck.general_settings.count = Some(count); deck.count = Some(count);
} }
SetOpenMode(mode) => { SetOpenMode(mode) => {
let deck = self.selected_deck_mut().unwrap(); let deck = self.selected_deck_mut().unwrap();
deck.general_settings.open_mode = mode; deck.open_mode = mode;
} }
SetAppendMode(mode) => { SetAppendMode(mode) => {
let deck = self.selected_deck_mut().unwrap(); let deck = self.selected_deck_mut().unwrap();
deck.append_mode = mode; deck.append_mode = mode;
} }
AppendWords(count) => { AppendWords(count) => {
let adding: Vec<usize>; let adding: Vec<EntityHandle<WordData>>;
{ {
{ {
let deck = self.selected_deck().unwrap(); let deck = self.selected_deck().unwrap();
@@ -257,22 +251,9 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
impl RepetitionsState { impl RepetitionsState {
pub(crate) fn new(state: AppState) -> RepetitionsState { pub(crate) fn new(state: AppState) -> RepetitionsState {
let state_ = state.lock(); let decks = Self::get_decks_from_state(&state);
let mut map = HashMap::with_capacity(state_.dictionary.len());
state_
.dictionary
.iter()
.enumerate()
.for_each(|(index, word)| {
map.insert(word.id, index);
});
let decks = Self::get_decks_from_state(&state_);
drop(state_);
RepetitionsState { RepetitionsState {
word_id_index_map: map, selected_deck_handle: None,
selected_deck_index: None,
decks, decks,
state, state,
} }
@@ -281,6 +262,7 @@ impl RepetitionsState {
fn get_decks_from_state(state: &AppState) -> Vec<DeckViewData> { fn get_decks_from_state(state: &AppState) -> Vec<DeckViewData> {
state state
.decks .decks
.read()
.iter() .iter()
.enumerate() .enumerate()
.map(|(index, deck)| DeckViewData { .map(|(index, deck)| DeckViewData {
@@ -289,7 +271,9 @@ impl RepetitionsState {
available_words_indices: Default::default(), available_words_indices: Default::default(),
indices_ready: false, indices_ready: false,
append_mode: Default::default(), append_mode: Default::default(),
count: None,
index: Some(index), index: Some(index),
open_mode: OrderMode::Default,
}) })
.collect() .collect()
} }
@@ -526,7 +510,7 @@ impl RepetitionsState {
text!("{} слова добавлено из {}", now, available).into() text!("{} слова добавлено из {}", now, available).into()
} }
fn count_view(&self, deck: &DeckSettings) -> Element<'_, RepetitionsMessage> { fn count_view(&self, deck: &DeckSettings) -> Element<'_, RepetitionsMessage> {
if let Some(count) = deck.count { if let Some(count) = self.decks.iter().find() {
return text!("Количество слов: {}", count).into(); return text!("Количество слов: {}", count).into();
} }
space().into() space().into()
@@ -578,7 +562,7 @@ impl RepetitionsState {
fn append_words( fn append_words(
state: &mut AppState, state: &mut AppState,
deck: &DeckSettings, deck: &DeckSettings,
indices: impl Iterator<Item = usize>, indices: impl Iterator<Item = EntityHandle<WordData>>,
) -> MaybeError { ) -> MaybeError {
let words = &state.dictionary; let words = &state.dictionary;
let stats = &mut indices let stats = &mut indices
@@ -591,7 +575,7 @@ impl RepetitionsState {
score: 1, score: 1,
fsrs_opened: Utc::now().date_naive(), fsrs_opened: Utc::now().date_naive(),
fsrs_memory: None, fsrs_memory: None,
set_id: deck.id, deck_id: deck.id,
fsrs_open_day: Utc::now().date_naive(), fsrs_open_day: Utc::now().date_naive(),
} }
}) })
@@ -605,32 +589,34 @@ impl RepetitionsState {
fn select_deck(&mut self, index: usize) { fn select_deck(&mut self, index: usize) {
if self.decks.get(index).is_some() { if self.decks.get(index).is_some() {
self.selected_deck_index = Some(index); self.selected_deck_handle = Some(index);
} }
} }
fn selected_deck(&self) -> Option<&DeckViewData> { fn selected_deck(&self) -> Option<&DeckViewData> {
self.decks.get(self.selected_deck_index?) self.decks.get(self.selected_deck_handle?)
} }
fn selected_deck_mut(&mut self) -> Option<&mut DeckViewData> { fn selected_deck_mut(&mut self) -> Option<&mut DeckViewData> {
self.decks.get_mut(self.selected_deck_index?) self.decks.get_mut(self.selected_deck_handle?)
} }
fn clear_selection(&mut self) { fn clear_selection(&mut self) {
self.selected_deck_index = None; self.selected_deck_handle = None;
} }
fn fill_deck_word_indices(&mut self) -> MaybeError { fn fill_deck_word_indices(&mut self) -> MaybeError {
let state = &self.state.lock(); let card_states = self.state.card_states.read();
let deck_id = self.selected_deck().unwrap().id;
let added = card_states
.query_par(Arc::new(move |state| state.deck_id == deck_id))
.iter(&card_states)
.map(|state| EntityHandle::from_id(state.word_id))
.collect::<Vec<_>>();
let mut deck = self.selected_deck().unwrap().clone(); let mut deck = self.selected_deck().unwrap().clone();
let added: Vec<_> = load_stats_of_deck(&deck, &state.connection)? let total = DeckData::list(&deck, &self.state)?;
.iter()
.map(|c| self.word_id_index_map[&c.word_id])
.collect();
let total = deck.get_word_list(state);
deck.existing_words_indices = added; deck.existing_words_indices = added;
deck.available_words_indices = total; deck.available_words_indices = total;
self.decks[self.selected_deck_index.unwrap()] = deck; self.decks[self.selected_deck_handle.unwrap()] = deck;
Ok(()) Ok(())
} }
} }
@@ -658,11 +644,12 @@ pub enum RepetitionsMessage {
#[derive(Clone)] #[derive(Clone)]
struct DeckViewData { struct DeckViewData {
general_settings: DeckSettings, general_settings: DeckSettings,
existing_words_indices: Vec<usize>, existing_words_indices: Vec<EntityHandle<WordData>>,
available_words_indices: Vec<usize>, available_words_indices: Vec<EntityHandle<WordData>>,
indices_ready: bool, indices_ready: bool,
append_mode: AppendMode, append_mode: AppendMode,
index: Option<usize>, count: Option<usize>,
open_mode: OrderMode,
} }
impl Deref for DeckViewData { impl Deref for DeckViewData {
+47 -33
View File
@@ -1,4 +1,5 @@
use crate::app::{AppState, fill_state}; use crate::app::AppState;
use crate::data::repositories::Repository;
use crate::data_provider::settings::{delete_settings, set_setting}; use crate::data_provider::settings::{delete_settings, set_setting};
use crate::data_provider::web_api::*; use crate::data_provider::web_api::*;
use crate::navigation::Page::PreviousPage; use crate::navigation::Page::PreviousPage;
@@ -12,8 +13,6 @@ use iced::widget::container::rounded_box;
use iced::widget::{button, column, container, progress_bar, row, space, text, toggler}; use iced::widget::{button, column, container, progress_bar, row, space, text, toggler};
use iced::{Center, Element, Fill, Font, Length, Task}; use iced::{Center, Element, Fill, Font, Length, Task};
use log::error; use log::error;
use parking_lot::Mutex;
use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
#[derive(Clone)] #[derive(Clone)]
@@ -56,8 +55,7 @@ impl NavigatedPage<SyncMessage> for SyncState {
match message { match message {
Back => {} Back => {}
CopyKey => { CopyKey => {
let state = self.state.lock(); let key = self.state.sync_data.read().key.clone().unwrap();
let key = state.sync_data.key.clone().unwrap();
return iced::clipboard::write(key) return iced::clipboard::write(key)
.map(|_val: String| RootMessage::Sync(KeyCopied)); .map(|_val: String| RootMessage::Sync(KeyCopied));
} }
@@ -76,16 +74,20 @@ impl NavigatedPage<SyncMessage> for SyncState {
if !validate_id(&new_id) { if !validate_id(&new_id) {
return Task::none(); return Task::none();
} }
let mut state = self.state.lock(); let mut settings = self.state.sync_data.write();
state.sync_data.key = Some(new_id.clone()); settings.key = Some(new_id.clone());
if let Err(err) = set_setting("SYNC_KEY".to_string(), new_id, &state.connection) { if let Err(err) = set_setting(
"SYNC_KEY".to_string(),
new_id,
&self.state.connection.lock(),
) {
return push_error_task!(err); return push_error_task!(err);
} }
} }
Send => { Send => {
self.prepare_to_db_interaction(); self.prepare_to_db_interaction();
let id = self.state.lock().sync_data.key.clone().unwrap(); let id = self.state.sync_data.read().key.clone().unwrap();
let tasks = Task::batch([ let tasks = Task::batch([
Task::perform( Task::perform(
async { tokio::time::sleep(Duration::from_millis(200)).await }, async { tokio::time::sleep(Duration::from_millis(200)).await },
@@ -97,7 +99,7 @@ impl NavigatedPage<SyncMessage> for SyncState {
return tasks; return tasks;
} }
GetLast => { GetLast => {
let id = self.state.lock().sync_data.key.clone().unwrap(); let id = self.state.sync_data.read().key.clone().unwrap();
let tasks = Task::batch([ let tasks = Task::batch([
Task::perform( Task::perform(
async { tokio::time::sleep(Duration::from_millis(200)).await }, async { tokio::time::sleep(Duration::from_millis(200)).await },
@@ -122,26 +124,27 @@ impl NavigatedPage<SyncMessage> for SyncState {
} }
NetworkFinished => { NetworkFinished => {
self.frozen = false; self.frozen = false;
let mut updated_state = AppState::new(); {
fill_state(&mut updated_state); let mut connection = self.state.connection.lock();
connection.restart();
}
if let Err(err) = self.reload_data() {
return push_error_task!(err);
}
let mut state = self.state.lock();
state.sync_data = updated_state.sync_data;
state.connection = updated_state.connection;
state.decks = updated_state.decks;
state.dictionary = updated_state.dictionary;
state.word_groups = updated_state.word_groups;
return Task::done(RootMessage::PushNotification(NotificationRequest::Info( return Task::done(RootMessage::PushNotification(NotificationRequest::Info(
NotificationData::DataLoaded, NotificationData::DataLoaded,
))); )));
} }
Disable => {} Disable => {}
DisableSync => { DisableSync => {
let mut state = self.state.lock(); let mut sync_data = self.state.sync_data.write();
state.sync_data.key = None; let connection = self.state.connection.lock();
sync_data.key = None;
let save_result = || { let save_result = || {
delete_settings("SYNC_KEY".to_string(), &state.connection)?; delete_settings("SYNC_KEY".to_string(), &connection)?;
delete_settings("AUTO_WEB_FETCH".to_string(), &state.connection)?; delete_settings("AUTO_WEB_FETCH".to_string(), &connection)?;
Ok::<(), NotificationData>(()) Ok::<(), NotificationData>(())
}; };
@@ -151,12 +154,14 @@ impl NavigatedPage<SyncMessage> for SyncState {
} }
SwitchAutoSync => { SwitchAutoSync => {
self.auto_fetch = !self.auto_fetch; self.auto_fetch = !self.auto_fetch;
let mut state = self.state.lock(); let mut sync_data = self.state.sync_data.write();
state.sync_data.auto_web_fetch = self.auto_fetch; let connection = self.state.connection.lock();
sync_data.auto_web_fetch = self.auto_fetch;
if let Err(err) = set_setting( if let Err(err) = set_setting(
"AUTO_WEB_FETCH".to_string(), "AUTO_WEB_FETCH".to_string(),
self.auto_fetch.to_string(), self.auto_fetch.to_string(),
&state.connection, &connection,
) { ) {
return push_error_task!(err); return push_error_task!(err);
} }
@@ -178,10 +183,8 @@ impl NavigatedPage<SyncMessage> for SyncState {
impl SyncState { impl SyncState {
pub fn new(state: AppState) -> SyncState { pub fn new(state: AppState) -> SyncState {
let auto_fetch; let auto_fetch = state.sync_data.read().auto_web_fetch;
{
auto_fetch = state.lock().sync_data.auto_web_fetch;
}
Self { Self {
auto_fetch, auto_fetch,
state, state,
@@ -190,6 +193,15 @@ impl SyncState {
} }
} }
fn reload_data(&mut self) -> Result<(), NotificationData> {
self.state.card_states.write().reload()?;
self.state.word_groups.write().reload()?;
self.state.decks.write().reload()?;
self.state.dictionary.write().reload()?;
self.state.history.write().reload()?;
Ok(())
}
fn sync_column(&self) -> Element<'_, SyncMessage> { fn sync_column(&self) -> Element<'_, SyncMessage> {
let network_view: Element<'_, SyncMessage> = if self.frozen { let network_view: Element<'_, SyncMessage> = if self.frozen {
progress_bar(0.0..=5.0, self.progress).into() progress_bar(0.0..=5.0, self.progress).into()
@@ -197,7 +209,7 @@ impl SyncState {
space().into() space().into()
}; };
{ {
if let Some(key) = self.state.lock().sync_data.key.clone() { if let Some(key) = self.state.sync_data.read().key.as_ref() {
column![ column![
text!("Ваш ключ синхронизации"), text!("Ваш ключ синхронизации"),
container( container(
@@ -254,13 +266,15 @@ impl SyncState {
} }
self.frozen = true; self.frozen = true;
self.progress = 0.0; self.progress = 0.0;
let state = self.state.lock(); let mut connection = self.state.connection.lock();
state
.connection connection
.query_row("PRAGMA wal_checkpoint(TRUNCATE)", [], |_| Ok(())) .query_row("PRAGMA wal_checkpoint(TRUNCATE)", [], |_| Ok(()))
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
error!("Ошибка при checkpoint WAL: {e}"); error!("Ошибка при checkpoint WAL: {e}");
}); });
connection.finish();
} }
} }