Partial AppState rewrite

This commit is contained in:
micialware committed 2026-08-31 11:46:35 +03:00
1 parent 29a90d48d9
commit 0c4aec3dc0
13 files changed
+75 -49

No files matched your search

+15 -11
View File
@@ -1,9 +1,10 @@
use std::sync::Arc;
use crate::data::Id; use crate::data::Id;
use crate::data::entities::DeckSettings; use crate::data::entities::DeckSettings;
use crate::data::entities::{WordData, WordGroup}; use crate::data::entities::{WordData, WordGroup};
use crate::data_provider::decks::load_sets; use crate::data_provider::decks::load_sets;
use crate::data_provider::settings::get_setting; use crate::data_provider::settings::get_setting;
use crate::data_provider::sqlite::default_connection; use crate::data_provider::sqlite::{SqliteConnection};
use crate::data_provider::words::{load_word_groups, load_words}; use crate::data_provider::words::{load_word_groups, load_words};
use crate::navigation::RootMessage::Keyboard; use crate::navigation::RootMessage::Keyboard;
use crate::navigation::{AppSettings, RootMessage, ScreenState}; use crate::navigation::{AppSettings, RootMessage, ScreenState};
@@ -15,6 +16,7 @@ use iced_core::window::Position;
use iced_core::window::settings::PlatformSpecific; use iced_core::window::settings::PlatformSpecific;
use iced_core::{Font, Size, Theme}; use iced_core::{Font, Size, Theme};
use log::info; use log::info;
use parking_lot::RwLock;
use rusqlite::Connection; use rusqlite::Connection;
pub const USER_FONT: Font = Font::with_name("Noto Sans JP"); pub const USER_FONT: Font = Font::with_name("Noto Sans JP");
@@ -57,12 +59,13 @@ fn subscription(_state: &ScreenState) -> Subscription<RootMessage> {
keyboard::listen().map(Keyboard) keyboard::listen().map(Keyboard)
} }
#[derive(Clone)]
pub struct AppState { pub struct AppState {
pub dictionary: Vec<WordData>, pub dictionary: Vec<WordData>,
pub decks: Vec<DeckSettings>, pub decks: Vec<DeckSettings>,
pub word_groups: Vec<WordGroup>, pub word_groups: Vec<WordGroup>,
pub connection: Connection, pub connection: Arc<RwLock<SqliteConnection>>,
pub sync_data: AppSettings, pub sync_data: Arc<RwLock<AppSettings>>,
pub activity: HashMap<Id, Vec<(NaiveDate, u32)>>, pub activity: HashMap<Id, Vec<(NaiveDate, u32)>>,
} }
@@ -78,26 +81,27 @@ impl AppState {
dictionary: vec![], dictionary: vec![],
decks: vec![], decks: vec![],
word_groups: vec![], word_groups: vec![],
connection: default_connection(), connection: Arc::new(RwLock::new(Default::default())),
sync_data: AppSettings { sync_data: Arc::new(RwLock::new(AppSettings {
key: None, key: None,
auto_web_fetch: false, auto_web_fetch: false,
}, })),
activity: Default::default(), activity: Default::default(),
} }
} }
} }
pub fn fill_state(state: &mut AppState) { pub fn fill_state(state: &mut AppState) {
let list = load_words(&state.connection); let connection = state.connection.read();
let sets = load_sets(&state.connection); let list = load_words(&connection);
let groups = load_word_groups(&state.connection); let sets = load_sets(&connection);
let setting = load_settings(&state.connection); let groups = load_word_groups(&connection);
let setting = load_settings(&connection);
state.dictionary = list.unwrap_or_default(); state.dictionary = list.unwrap_or_default();
state.decks = sets.unwrap_or_default(); state.decks = sets.unwrap_or_default();
state.word_groups = groups.unwrap_or_default(); state.word_groups = groups.unwrap_or_default();
state.sync_data = setting state.sync_data = Arc::new(RwLock::new(setting))
} }
fn load_settings(connection: &Connection) -> AppSettings { fn load_settings(connection: &Connection) -> AppSettings {
+6 -9
View File
@@ -9,15 +9,13 @@ use crate::data_provider::card_states::{load_stats_of_deck, update_stat_score};
use crate::data_provider::history::push_note; use crate::data_provider::history::push_note;
use crate::notification::{MaybeError, NotificationData}; use crate::notification::{MaybeError, NotificationData};
use chrono::Utc; use chrono::Utc;
use parking_lot::Mutex;
use std::sync::Arc;
#[derive(Clone)] #[derive(Clone)]
pub struct DeckData { pub struct DeckData {
pub(crate) words: Vec<WordData>, pub(crate) words: Vec<WordData>,
pub(crate) set: Vec<CardState>, pub(crate) set: Vec<CardState>,
current_word_index: Option<usize>, current_word_index: Option<usize>,
state: Arc<Mutex<AppState>>, state: AppState,
order_module: OrderModule, order_module: OrderModule,
open_mode: OrderMode, open_mode: OrderMode,
settings: DeckSettings, settings: DeckSettings,
@@ -25,21 +23,20 @@ pub struct DeckData {
impl DeckData { impl DeckData {
pub fn new( pub fn new(
settings: &DeckSettings, settings: &DeckSettings,
state: Arc<Mutex<AppState>>, state: AppState,
) -> Result<Self, NotificationData> { ) -> Result<Self, NotificationData> {
let state_for = state.clone(); let state_for = state.clone();
let state_locked = state.lock();
let stats = load_stats_of_deck(settings, &state_locked.connection)?; let stats = load_stats_of_deck(settings, &state.connection.read())?;
let words = stats let words = stats
.iter() .iter()
.map(|stat| { .map(|stat| {
state_locked state
.dictionary .dictionary
.binary_search_by_key(&stat.word_id, |w| w.id) .binary_search_by_key(&stat.word_id, |w| w.id)
.expect("No word found in dictionary") .expect("No word found in dictionary")
}) })
.map(|index| &state_locked.dictionary[index]) .map(|index| &state.dictionary[index])
.cloned() .cloned()
.collect(); .collect();
@@ -117,7 +114,7 @@ impl DeckData {
OrderMode::FullRandom => RandomSRS(RandomSRSModule::new()), OrderMode::FullRandom => RandomSRS(RandomSRSModule::new()),
} }
} }
update_stat_score(word, &self.state.lock().connection)?; update_stat_score(word, &self.state.connection.read())?;
let _ = push_note( let _ = push_note(
self.settings.id, self.settings.id,
HistoryItem { HistoryItem {
+27
View File
@@ -1,5 +1,6 @@
use crate::fs::*; use crate::fs::*;
use rusqlite::Connection; use rusqlite::Connection;
use std::ops::{Deref, DerefMut};
pub fn create_db() { pub fn create_db() {
let db_file = db_path(); let db_file = db_path();
@@ -84,3 +85,29 @@ pub fn default_connection() -> Connection {
.expect("Failed to set PRAGMA"); .expect("Failed to set PRAGMA");
connection connection
} }
pub struct SqliteConnection(Option<Connection>);
impl Deref for SqliteConnection {
type Target = Connection;
fn deref(&self) -> &Self::Target {
self.0.as_ref().unwrap()
}
}
impl DerefMut for SqliteConnection {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut().unwrap()
}
}
impl Default for SqliteConnection {
fn default() -> Self {
SqliteConnection(Some(default_connection()))
}
}
impl SqliteConnection {
pub fn finish(&mut self) {
self.0 = None;
}
}
+10 -12
View File
@@ -1,7 +1,7 @@
use crate::app::{AppState, fill_state}; use crate::app::{AppState, fill_state};
use crate::data::Id; use crate::data::Id;
use crate::data_provider::history::get_history_of_set; use crate::data_provider::history::get_history_of_set;
use crate::data_provider::sqlite::{create_db, default_connection}; use crate::data_provider::sqlite::{create_db, default_connection, SqliteConnection};
use crate::data_provider::web_api::{ 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,
}; };
@@ -47,7 +47,6 @@ impl Default for ScreenState {
fn default() -> Self { fn default() -> Self {
let mut state = AppState::new(); let mut state = AppState::new();
fill_state(&mut state); fill_state(&mut state);
let state = Arc::new(Mutex::new(state));
ScreenState { ScreenState {
stack: vec![Selector(SelectorState::new(state.clone()))], stack: vec![Selector(SelectorState::new(state.clone()))],
app_state: state.clone(), app_state: state.clone(),
@@ -99,7 +98,7 @@ pub enum Page {
pub struct ScreenState { pub struct ScreenState {
stack: Vec<Page>, stack: Vec<Page>,
app_state: Arc<Mutex<AppState>>, app_state: AppState,
notification_manager: NotificationManager, notification_manager: NotificationManager,
} }
@@ -114,9 +113,9 @@ impl ScreenState {
}); });
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;
if state_guard.sync_data.auto_web_fetch if state_guard.sync_data.read().auto_web_fetch
&& let Some(key) = state_guard.sync_data.key.clone() && let Some(key) = state_guard.sync_data.read().key.clone()
{ {
final_task = Task::batch([ final_task = Task::batch([
final_task, final_task,
@@ -133,7 +132,6 @@ impl ScreenState {
]); ]);
} }
drop(state_guard);
info!("Boot finished"); info!("Boot finished");
(state, final_task) (state, final_task)
} }
@@ -192,15 +190,15 @@ impl ScreenState {
} }
if let DataLoaded(data) = message { if let DataLoaded(data) = message {
self.app_state.lock().activity = data; self.app_state.activity = data;
return Task::none(); return Task::none();
} }
if let UpdateData = message { if let UpdateData = message {
info!("Loading data"); info!("Loading data");
let mut state = self.app_state.lock(); let state = &mut self.app_state;
if cfg!(windows) { if cfg!(windows) {
state.connection = Connection::open_in_memory().unwrap(); state.connection.write().finish();
} }
let db_file = db_path(); let db_file = db_path();
let temp_db_file = temp_db_path(); let temp_db_file = temp_db_path();
@@ -208,8 +206,8 @@ impl ScreenState {
return push_error_task!(PermissionDenied); return push_error_task!(PermissionDenied);
} }
state.connection = default_connection(); state.connection = Default::default();
fill_state(&mut state); fill_state(state);
return Task::none(); return Task::none();
} }
+2 -2
View File
@@ -30,7 +30,7 @@ use std::time::{Duration, Instant};
#[derive(Clone)] #[derive(Clone)]
pub struct DictionaryState { pub struct DictionaryState {
state: Arc<Mutex<AppState>>, state: AppState,
include_map: Vec<bool>, include_map: Vec<bool>,
tag_map: HashMap<String, bool>, tag_map: HashMap<String, bool>,
reverse: bool, reverse: bool,
@@ -300,7 +300,7 @@ impl NavigatedPage<DictionaryMessage> for DictionaryState {
} }
impl DictionaryState { impl DictionaryState {
pub fn new(state: Arc<Mutex<AppState>>) -> Self { pub fn new(state: AppState) -> Self {
let len = state.lock().dictionary.len(); let len = state.lock().dictionary.len();
let mut result = DictionaryState { let mut result = DictionaryState {
+1 -1
View File
@@ -48,7 +48,7 @@ impl NavigatedPage<HistoryMessage> for HistoryState {
} }
impl HistoryState { impl HistoryState {
pub fn new(id: crate::data::Id, state: Arc<Mutex<AppState>>) -> Self { pub fn new(id: crate::data::Id, state: AppState) -> Self {
let state = state.lock(); let state = state.lock();
let history = get_history_of_set(id).unwrap_or_default(); let history = get_history_of_set(id).unwrap_or_default();
let words = history let words = history
+2 -2
View File
@@ -34,7 +34,7 @@ const DEFAULT_FIELDS: [&str; 6] = ["key", "value", "tags", "reading", "context",
#[derive(Clone)] #[derive(Clone)]
pub struct ImportState { pub struct ImportState {
state: Arc<Mutex<AppState>>, state: AppState,
path: Option<PathBuf>, path: Option<PathBuf>,
import_data: Option<ImportData>, import_data: Option<ImportData>,
selected_index: usize, selected_index: usize,
@@ -318,7 +318,7 @@ impl ImportState {
} }
impl ImportState { impl ImportState {
pub fn new(state: Arc<Mutex<AppState>>) -> ImportState { pub fn new(state: AppState) -> ImportState {
ImportState { ImportState {
state, state,
path: None, path: None,
+2 -2
View File
@@ -22,7 +22,7 @@ use std::sync::Arc;
use tokio::task::spawn_blocking; use tokio::task::spawn_blocking;
pub struct RepetitionState { pub struct RepetitionState {
state: Arc<Mutex<AppState>>, state: AppState,
pub settings: DeckSettings, pub settings: DeckSettings,
pub set: DeckData, pub set: DeckData,
current_word: WordData, current_word: WordData,
@@ -104,7 +104,7 @@ impl NavigatedPage<RepetitionMessage> for RepetitionState {
impl RepetitionState { impl RepetitionState {
pub(crate) fn new( pub(crate) fn new(
set: DeckSettings, set: DeckSettings,
state: Arc<Mutex<AppState>>, state: AppState,
) -> Result<RepetitionState, NotificationData> { ) -> Result<RepetitionState, NotificationData> {
let mut card_set = DeckData::new(&set, state.clone())?; let mut card_set = DeckData::new(&set, state.clone())?;
let (word, stat) = card_set.next(); let (word, stat) = card_set.next();
+2 -2
View File
@@ -21,14 +21,14 @@ use std::time::Duration;
pub struct RepetitionSettingsState { pub struct RepetitionSettingsState {
set: DeckSettings, set: DeckSettings,
index: usize, index: usize,
state: Arc<Mutex<AppState>>, state: AppState,
real_delete: bool, real_delete: bool,
correct_filter: bool, correct_filter: bool,
filter_changed: bool, filter_changed: bool,
} }
impl RepetitionSettingsState { impl RepetitionSettingsState {
pub(crate) fn new(index: usize, state: Arc<Mutex<AppState>>) -> RepetitionSettingsState { pub(crate) fn new(index: usize, state: AppState) -> RepetitionSettingsState {
let set; let set;
{ {
let local_state = state.lock(); let local_state = state.lock();
+2 -2
View File
@@ -36,7 +36,7 @@ pub struct RepetitionsState {
word_id_index_map: HashMap<Id, usize>, word_id_index_map: HashMap<Id, usize>,
selected_deck_index: Option<usize>, selected_deck_index: Option<usize>,
decks: Vec<DeckViewData>, decks: Vec<DeckViewData>,
state: Arc<Mutex<AppState>>, state: AppState,
} }
impl NavigatedPage<RepetitionsMessage> for RepetitionsState { impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
@@ -257,7 +257,7 @@ impl NavigatedPage<RepetitionsMessage> for RepetitionsState {
} }
impl RepetitionsState { impl RepetitionsState {
pub(crate) fn new(state: Arc<Mutex<AppState>>) -> RepetitionsState { pub(crate) fn new(state: AppState) -> RepetitionsState {
let state_ = state.lock(); let state_ = state.lock();
let mut map = HashMap::with_capacity(state_.dictionary.len()); let mut map = HashMap::with_capacity(state_.dictionary.len());
+2 -2
View File
@@ -22,7 +22,7 @@ use std::sync::Arc;
pub struct SelectorState { pub struct SelectorState {
pub set: KanaSet, pub set: KanaSet,
is_writing: bool, is_writing: bool,
state: Arc<Mutex<AppState>>, state: AppState,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -114,7 +114,7 @@ impl NavigatedPage<SelectorMessage> for SelectorState {
} }
impl SelectorState { impl SelectorState {
pub fn new(state: Arc<Mutex<AppState>>) -> Self { pub fn new(state: AppState) -> Self {
Self { Self {
set: Default::default(), set: Default::default(),
is_writing: false, is_writing: false,
+2 -2
View File
@@ -34,7 +34,7 @@ pub enum SyncMessage {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct SyncState { pub struct SyncState {
state: Arc<Mutex<AppState>>, state: AppState,
auto_fetch: bool, auto_fetch: bool,
frozen: bool, frozen: bool,
progress: f32, progress: f32,
@@ -177,7 +177,7 @@ impl NavigatedPage<SyncMessage> for SyncState {
} }
impl SyncState { impl SyncState {
pub fn new(state: Arc<Mutex<AppState>>) -> SyncState { pub fn new(state: AppState) -> SyncState {
let auto_fetch; let auto_fetch;
{ {
auto_fetch = state.lock().sync_data.auto_web_fetch; auto_fetch = state.lock().sync_data.auto_web_fetch;
+2 -2
View File
@@ -15,7 +15,7 @@ use std::sync::Arc;
#[derive(Clone)] #[derive(Clone)]
pub struct WordState { pub struct WordState {
state: Arc<Mutex<AppState>>, state: AppState,
index: usize, index: usize,
word: WordData, word: WordData,
} }
@@ -136,7 +136,7 @@ impl NavigatedPage<WordMessage> for WordState {
} }
impl WordState { impl WordState {
pub(crate) fn new(word: WordData, index: usize, state: Arc<Mutex<AppState>>) -> WordState { pub(crate) fn new(word: WordData, index: usize, state: AppState) -> WordState {
WordState { state, index, word } WordState { state, index, word }
} }
} }