From 3d7f313c18099066ebc828155e62d92e6a964e9d Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Wed, 11 May 2022 22:39:46 -0400 Subject: [PATCH] store previous function data in local storage This should maybe be done through website's hash instead? but idk --- Cargo.lock | 12 ++++----- src/function_entry.rs | 53 ++++++++++++++++++++++++++++++++++++- src/function_manager.rs | 45 ++++++++++++++++++++++++++++++++ src/math_app.rs | 58 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 158 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16e6efc..8076585 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -668,7 +668,7 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "eframe" version = "0.18.0" -source = "git+https://github.com/Titaniumtown/egui.git#2bfdd60400da7f1f7139e58858bc4910d166f1a0" +source = "git+https://github.com/Titaniumtown/egui.git#49b732b071a0e5e2eb7dbb6896cd7bf1c3ca687d" dependencies = [ "bytemuck", "egui", @@ -688,7 +688,7 @@ dependencies = [ [[package]] name = "egui" version = "0.18.1" -source = "git+https://github.com/Titaniumtown/egui.git#2bfdd60400da7f1f7139e58858bc4910d166f1a0" +source = "git+https://github.com/Titaniumtown/egui.git#49b732b071a0e5e2eb7dbb6896cd7bf1c3ca687d" dependencies = [ "ahash", "epaint", @@ -699,7 +699,7 @@ dependencies = [ [[package]] name = "egui-winit" version = "0.18.0" -source = "git+https://github.com/Titaniumtown/egui.git#2bfdd60400da7f1f7139e58858bc4910d166f1a0" +source = "git+https://github.com/Titaniumtown/egui.git#49b732b071a0e5e2eb7dbb6896cd7bf1c3ca687d" dependencies = [ "arboard", "egui", @@ -712,7 +712,7 @@ dependencies = [ [[package]] name = "egui_glow" version = "0.18.1" -source = "git+https://github.com/Titaniumtown/egui.git#2bfdd60400da7f1f7139e58858bc4910d166f1a0" +source = "git+https://github.com/Titaniumtown/egui.git#49b732b071a0e5e2eb7dbb6896cd7bf1c3ca687d" dependencies = [ "bytemuck", "egui", @@ -732,7 +732,7 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "emath" version = "0.18.0" -source = "git+https://github.com/Titaniumtown/egui.git#2bfdd60400da7f1f7139e58858bc4910d166f1a0" +source = "git+https://github.com/Titaniumtown/egui.git#49b732b071a0e5e2eb7dbb6896cd7bf1c3ca687d" dependencies = [ "bytemuck", "serde", @@ -741,7 +741,7 @@ dependencies = [ [[package]] name = "epaint" version = "0.18.1" -source = "git+https://github.com/Titaniumtown/egui.git#2bfdd60400da7f1f7139e58858bc4910d166f1a0" +source = "git+https://github.com/Titaniumtown/egui.git#49b732b071a0e5e2eb7dbb6896cd7bf1c3ca687d" dependencies = [ "ab_glyph", "ahash", diff --git a/src/function_entry.rs b/src/function_entry.rs index d90f260..80ae2e6 100644 --- a/src/function_entry.rs +++ b/src/function_entry.rs @@ -8,8 +8,9 @@ use egui::{ Checkbox, Context, }; use epaint::Color32; -use parsing::AutoComplete; +use parsing::{generate_hint, AutoComplete}; use parsing::{process_func_str, BackingFunction}; +use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer}; use std::{ fmt::{self, Debug}, intrinsics::assume, @@ -66,6 +67,56 @@ pub struct FunctionEntry { pub settings_opened: bool, } +impl Serialize for FunctionEntry { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = serializer.serialize_struct("FunctionEntry", 4)?; + s.serialize_field("raw_func_str", &self.raw_func_str)?; + s.serialize_field("integral", &self.integral)?; + s.serialize_field("derivative", &self.derivative)?; + s.serialize_field("curr_nth", &self.curr_nth)?; + + s.end() + } +} + +impl<'de> Deserialize<'de> for FunctionEntry { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct Helper { + raw_func_str: String, + integral: bool, + derivative: bool, + curr_nth: usize, + } + + let helper = Helper::deserialize(deserializer)?; + let mut new_func_entry = FunctionEntry::EMPTY; + let gen_func = BackingFunction::new(&helper.raw_func_str); + match gen_func { + Ok(func) => new_func_entry.function = func, + Err(x) => new_func_entry.test_result = Some(x), + } + + new_func_entry.autocomplete = AutoComplete { + i: 0, + hint: generate_hint(&helper.raw_func_str), + string: helper.raw_func_str, + }; + + new_func_entry.integral = helper.integral; + new_func_entry.derivative = helper.derivative; + new_func_entry.curr_nth = helper.curr_nth; + + Ok(new_func_entry) + } +} + impl const Default for FunctionEntry { /// Creates default FunctionEntry instance (which is empty) fn default() -> FunctionEntry { FunctionEntry::EMPTY } diff --git a/src/function_manager.rs b/src/function_manager.rs index 470f4bd..87ea8ff 100644 --- a/src/function_manager.rs +++ b/src/function_manager.rs @@ -5,6 +5,11 @@ use egui::{Button, Id, Key, Modifiers, TextEdit, WidgetText}; use emath::vec2; use parsing::Hint; use parsing::Movement; +use serde::ser::SerializeStruct; +use serde::Deserialize; +use serde::Deserializer; +use serde::Serialize; +use serde::Serializer; use std::ops::BitXorAssign; use uuid::Uuid; @@ -23,6 +28,46 @@ impl Default for FunctionManager { } } +impl Serialize for FunctionManager { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = serializer.serialize_struct("FunctionManager", 1)?; + s.serialize_field( + "data", + &self + .functions + .iter() + .cloned() + .map(|(id, func)| (id.value(), func)) + .collect::>(), + )?; + s.end() + } +} + +impl<'de> Deserialize<'de> for FunctionManager { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct Helper(Vec<(u64, FunctionEntry)>); + + let helper = Helper::deserialize(deserializer)?; + + Ok(FunctionManager { + functions: helper + .0 + .iter() + .cloned() + .map(|(id, func)| (egui::Id::new_from_u64(id), func)) + .collect::>(), + }) + } +} + /// Function that creates button that's used with the `button_area` const fn button_area_button(text: impl Into) -> Button { Button::new(text).frame(false) diff --git a/src/math_app.rs b/src/math_app.rs index a5b2739..d49ce68 100644 --- a/src/math_app.rs +++ b/src/math_app.rs @@ -10,7 +10,7 @@ use egui::{ }; use emath::{Align, Align2}; use epaint::Rounding; -use instant::Duration; +use instant::{Duration, Instant}; use std::{io::Read, ops::BitXorAssign}; #[cfg(threading)] @@ -98,6 +98,9 @@ pub struct MathApp { /// Stores settings (pretty self-explanatory) settings: AppSettings, + + #[cfg(target_arch = "wasm32")] + since_last_save: Instant, } impl MathApp { @@ -111,7 +114,7 @@ impl MathApp { tracing::info!("Threading: Disabled"); tracing::info!("Initializing..."); - let start = instant::Instant::now(); + let start = Instant::now(); cfg_if::cfg_if! { if #[cfg(target_arch = "wasm32")] { @@ -164,12 +167,33 @@ impl MathApp { panic!("unable to get local storage") } } + + fn get_functions() -> Option { + if let Ok(Some(data)) = web_sys::window().expect("Could not get web_sys window").local_storage().unwrap().unwrap().get_item("YTBN-FUNCTIONS") { + let (commit, func_data) = crate::misc::storage_read(data); + + if commit == build::SHORT_COMMIT { + tracing::info!("Reading old functions"); + let function_manager: FunctionManager = bincode::deserialize(&func_data).unwrap(); + return Some(function_manager); + } else { + // is invalid + None + } + + } else { + None + } + } + } else { const fn get_storage_decompressed() -> Option> { None } const fn set_storage_decompressed(_: &Vec) {} + + const fn get_functions() -> Option { None } } } @@ -214,12 +238,14 @@ impl MathApp { loading_element.remove(); Self { - functions: Default::default(), + functions: get_functions().unwrap_or(FunctionManager::default()), last_info: (vec![None], None), dark_mode: true, // dark mode is default and is previously set text: data.text, opened: Opened::default(), settings: Default::default(), + #[cfg(target_arch = "wasm32")] + since_last_save: Instant::now(), } } @@ -562,5 +588,31 @@ impl App for MathApp { // Calculate and store the last time it took to draw the frame self.last_info.1 = start.map(|a| a.elapsed()); + + #[cfg(target_arch = "wasm32")] + { + if self.since_last_save.elapsed().as_millis() > 10000 { + self.since_last_save = Instant::now(); + if let Ok(Some(local_storage)) = web_sys::window() + .expect("Could not get web_sys window") + .local_storage() + { + tracing::info!("Setting current functions"); + let saved_data = &crate::misc::storage_create( + &build::SHORT_COMMIT + .chars() + .map(|c| c as u8) + .collect::>(), + bincode::serialize(&self.functions).unwrap().as_slice(), + ); + tracing::info!("Data has length of {}", saved_data.len()); + local_storage + .set_item("YTBN-FUNCTIONS", saved_data) + .expect("failed to set local function storage"); + } else { + panic!("unable to get local storage") + } + } + } } }