mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 04:40:03 -04:00
[egui_web] Auto-save app state to Local Storage every 30 seconds
This commit is contained in:
@@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added ⭐
|
||||
|
||||
* Auto-save of app state to local storage
|
||||
|
||||
### Changed ⭐
|
||||
|
||||
* Set a maximum canvas size to alleviate performance issues on some machines
|
||||
|
||||
@@ -12,19 +12,16 @@ pub struct WebBackend {
|
||||
painter: webgl::Painter,
|
||||
previous_frame_time: Option<f32>,
|
||||
frame_start: Option<f64>,
|
||||
last_save_time: Option<f64>,
|
||||
}
|
||||
|
||||
impl WebBackend {
|
||||
pub fn new(canvas_id: &str) -> Result<Self, JsValue> {
|
||||
let ctx = egui::CtxRef::default();
|
||||
load_memory(&ctx);
|
||||
Ok(Self {
|
||||
ctx,
|
||||
painter: webgl::Painter::new(canvas_id)?,
|
||||
previous_frame_time: None,
|
||||
frame_start: None,
|
||||
last_save_time: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -47,8 +44,6 @@ impl WebBackend {
|
||||
let (output, paint_commands) = self.ctx.end_frame();
|
||||
let paint_jobs = self.ctx.tesselate(paint_commands);
|
||||
|
||||
self.auto_save();
|
||||
|
||||
let now = now_sec();
|
||||
self.previous_frame_time = Some((now - frame_start) as f32);
|
||||
|
||||
@@ -68,16 +63,6 @@ impl WebBackend {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn auto_save(&mut self) {
|
||||
let now = now_sec();
|
||||
let time_since_last_save = now - self.last_save_time.unwrap_or(std::f64::NEG_INFINITY);
|
||||
const AUTO_SAVE_INTERVAL: f64 = 5.0;
|
||||
if time_since_last_save > AUTO_SAVE_INTERVAL {
|
||||
self.last_save_time = Some(now);
|
||||
save_memory(&self.ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn painter_debug_info(&self) -> String {
|
||||
self.painter.debug_info()
|
||||
}
|
||||
@@ -159,19 +144,37 @@ pub struct AppRunner {
|
||||
pub input: WebInput,
|
||||
pub app: Box<dyn App>,
|
||||
pub needs_repaint: std::sync::Arc<NeedRepaint>,
|
||||
pub storage: LocalStorage,
|
||||
pub last_save_time: f64,
|
||||
}
|
||||
|
||||
impl AppRunner {
|
||||
pub fn new(web_backend: WebBackend, mut app: Box<dyn App>) -> Result<Self, JsValue> {
|
||||
load_memory(&web_backend.ctx);
|
||||
let storage = LocalStorage::default();
|
||||
app.load(&storage);
|
||||
app.setup(&web_backend.ctx);
|
||||
Ok(Self {
|
||||
web_backend,
|
||||
input: Default::default(),
|
||||
app,
|
||||
needs_repaint: Default::default(),
|
||||
storage,
|
||||
last_save_time: now_sec(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn auto_save(&mut self) {
|
||||
let now = now_sec();
|
||||
let time_since_last_save = now - self.last_save_time;
|
||||
|
||||
if time_since_last_save > self.app.auto_save_interval().as_secs_f64() {
|
||||
save_memory(&self.web_backend.ctx);
|
||||
self.app.save(&mut self.storage);
|
||||
self.last_save_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn canvas_id(&self) -> &str {
|
||||
self.web_backend.canvas_id()
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ pub fn load_memory(ctx: &egui::Context) {
|
||||
*ctx.memory() = memory;
|
||||
}
|
||||
Err(err) => {
|
||||
console_log(format!("ERROR: Failed to parse memory json: {}", err));
|
||||
console_error(format!("Failed to parse memory json: {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,14 +164,12 @@ pub fn save_memory(ctx: &egui::Context) {
|
||||
local_storage_set("egui_memory_json", &json);
|
||||
}
|
||||
Err(err) => {
|
||||
console_log(format!(
|
||||
"ERROR: Failed to serialize memory as json: {}",
|
||||
err
|
||||
));
|
||||
console_error(format!("Failed to serialize memory as json: {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LocalStorage {}
|
||||
|
||||
impl egui::app::Storage for LocalStorage {
|
||||
@@ -220,7 +218,7 @@ pub fn set_clipboard_text(s: &str) {
|
||||
let future = wasm_bindgen_futures::JsFuture::from(promise);
|
||||
let future = async move {
|
||||
if let Err(err) = future.await {
|
||||
console_log(format!("Copy/cut action denied: {:?}", err));
|
||||
console_error(format!("Copy/cut action denied: {:?}", err));
|
||||
}
|
||||
};
|
||||
wasm_bindgen_futures::spawn_local(future);
|
||||
@@ -341,7 +339,9 @@ fn paint_and_schedule(runner_ref: AppRunnerRef) -> Result<(), JsValue> {
|
||||
if output.needs_repaint {
|
||||
runner_lock.needs_repaint.set_true();
|
||||
}
|
||||
runner_lock.auto_save();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user