Extract store invalidation detection into separate AppState

This commit is contained in:
Joscha 2025-05-26 23:45:58 +02:00
parent 0e7e54bf71
commit 46f5bc38b8
4 changed files with 75 additions and 50 deletions

View file

@ -1,18 +1,25 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use gdn::{ids::NoteId, store::Store}; use gdn::ids::NoteId;
use tauri::{AppHandle, Emitter, State}; use tauri::{AppHandle, Emitter, State};
use crate::types::{EventNotesStoreUpdate, Note}; use crate::{
state::AppState,
types::{EventNotesStoreUpdate, Note},
};
// API methods are sorted alphabetically. // API methods are sorted alphabetically.
fn update_if_required(store: &mut Store, app: &AppHandle) { fn update_if_required(state: &mut AppState, app: &AppHandle) {
if let Some(store_id) = store.needs_update() { let store_id = state.store.id();
if state.store_last_id == Some(store_id) {
// No update necessary if the id hasn't changed
return;
}
let payload = EventNotesStoreUpdate { store_id }; let payload = EventNotesStoreUpdate { store_id };
app.emit("notes_store_update", payload).unwrap(); app.emit("notes_store_update", payload).unwrap();
store.update(); state.store_last_id = Some(store_id)
}
} }
#[tauri::command] #[tauri::command]
@ -21,10 +28,12 @@ pub fn note_child_add(
child_id: NoteId, child_id: NoteId,
child_position: isize, child_position: isize,
app: AppHandle, app: AppHandle,
store: State<'_, Arc<Mutex<Store>>>, state: State<'_, Arc<Mutex<AppState>>>,
) { ) {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
guard.add_child_at_position(id, child_id, child_position); guard
.store
.add_child_at_position(id, child_id, child_position);
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
} }
@ -36,10 +45,12 @@ pub fn note_child_move(
to_id: NoteId, to_id: NoteId,
to_position: isize, to_position: isize,
app: AppHandle, app: AppHandle,
store: State<'_, Arc<Mutex<Store>>>, state: State<'_, Arc<Mutex<AppState>>>,
) { ) {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
guard.move_child_by_id_to_position(child_id, from_id, from_iteration, to_id, to_position); guard
.store
.move_child_by_id_to_position(child_id, from_id, from_iteration, to_id, to_position);
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
} }
@ -49,10 +60,12 @@ pub fn note_child_remove(
child_id: NoteId, child_id: NoteId,
child_iteration: usize, child_iteration: usize,
app: AppHandle, app: AppHandle,
store: State<'_, Arc<Mutex<Store>>>, state: State<'_, Arc<Mutex<AppState>>>,
) { ) {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
guard.remove_child_by_id(id, child_id, child_iteration); guard
.store
.remove_child_by_id(id, child_id, child_iteration);
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
} }
@ -61,32 +74,33 @@ pub fn note_children_set(
id: NoteId, id: NoteId,
children: Vec<NoteId>, children: Vec<NoteId>,
app: AppHandle, app: AppHandle,
store: State<'_, Arc<Mutex<Store>>>, state: State<'_, Arc<Mutex<AppState>>>,
) { ) {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
guard.set_children(id, children); guard.store.set_children(id, children);
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
} }
#[tauri::command] #[tauri::command]
pub fn note_create(text: String, app: AppHandle, store: State<'_, Arc<Mutex<Store>>>) -> Note { pub fn note_create(text: String, app: AppHandle, state: State<'_, Arc<Mutex<AppState>>>) -> Note {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
let id = guard.create(text); let id = guard.store.create(text);
let note = guard.store.get(id).unwrap().into();
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
guard.get(id).unwrap().into() note
} }
#[tauri::command] #[tauri::command]
pub fn note_delete(id: NoteId, app: AppHandle, store: State<'_, Arc<Mutex<Store>>>) { pub fn note_delete(id: NoteId, app: AppHandle, state: State<'_, Arc<Mutex<AppState>>>) {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
guard.delete(id); guard.store.delete(id);
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
} }
#[tauri::command] #[tauri::command]
pub fn note_get(id: NoteId, store: State<'_, Arc<Mutex<Store>>>) -> Option<Note> { pub fn note_get(id: NoteId, state: State<'_, Arc<Mutex<AppState>>>) -> Option<Note> {
let guard = store.lock().unwrap(); let guard = state.lock().unwrap();
guard.get(id).map(|it| it.into()) guard.store.get(id).map(|it| it.into())
} }
#[tauri::command] #[tauri::command]
@ -94,16 +108,16 @@ pub fn note_text_set(
id: NoteId, id: NoteId,
text: String, text: String,
app: AppHandle, app: AppHandle,
store: State<'_, Arc<Mutex<Store>>>, state: State<'_, Arc<Mutex<AppState>>>,
) { ) {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
guard.set_text(id, text); guard.store.set_text(id, text);
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
} }
#[tauri::command] #[tauri::command]
pub fn notes_clear(app: AppHandle, store: State<'_, Arc<Mutex<Store>>>) { pub fn notes_clear(app: AppHandle, state: State<'_, Arc<Mutex<AppState>>>) {
let mut guard = store.lock().unwrap(); let mut guard = state.lock().unwrap();
guard.clear(); guard.store.clear();
update_if_required(&mut guard, &app); update_if_required(&mut guard, &app);
} }

View file

@ -1,16 +1,21 @@
use serde_json as _; // Silence unused dependency warning use serde_json as _; // Silence unused dependency warning
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use gdn::store::Store; use crate::state::AppState;
mod api; mod api;
mod state;
mod types; mod types;
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
let state = Arc::new(Mutex::new(AppState::new()));
// TODO Launch store loading task
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_opener::init())
.manage(Arc::new(Mutex::new(Store::new()))) .manage(state)
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
api::note_child_add, api::note_child_add,
api::note_child_move, api::note_child_move,

View file

@ -0,0 +1,15 @@
use gdn::store::Store;
pub struct AppState {
pub store: Store,
pub store_last_id: Option<u64>,
}
impl AppState {
pub fn new() -> Self {
Self {
store: Store::new(),
store_last_id: None,
}
}
}

View file

@ -38,8 +38,7 @@ pub struct RichNote {
#[derive(Default)] #[derive(Default)]
pub struct Store { pub struct Store {
last_id: u64, id: u64,
curr_id: u64,
notes: HashMap<NoteId, RawNote>, notes: HashMap<NoteId, RawNote>,
parents: HashMap<NoteId, HashMap<NoteId, usize>>, parents: HashMap<NoteId, HashMap<NoteId, usize>>,
} }
@ -74,16 +73,8 @@ impl Store {
Repo { notes } Repo { notes }
} }
pub fn needs_update(&self) -> Option<u64> { pub fn id(&self) -> u64 {
if self.last_id != self.curr_id { self.id
Some(self.curr_id)
} else {
None
}
}
pub fn update(&mut self) {
self.last_id = self.curr_id;
} }
pub fn get(&self, id: NoteId) -> Option<RichNote> { pub fn get(&self, id: NoteId) -> Option<RichNote> {
@ -104,7 +95,7 @@ impl Store {
} }
fn tick(&mut self) { fn tick(&mut self) {
self.curr_id += 1; self.id += 1;
} }
fn make_consistent_and_tick(&mut self) { fn make_consistent_and_tick(&mut self) {