LinearSignal as a helper type

This commit is contained in:
Jeremy Wall 2023-07-22 16:14:23 -05:00
parent b496cf9568
commit 2ea0339ad1
4 changed files with 68 additions and 18 deletions

View File

@ -99,6 +99,7 @@ impl LocalStore {
.expect("Failed to set our app state"); .expect("Failed to set our app state");
} }
// TODO(jwall): Is this never used?
pub fn fetch_app_state(&self) -> Option<AppState> { pub fn fetch_app_state(&self) -> Option<AppState> {
self.store.get("app_state").map_or(None, |val| { self.store.get("app_state").map_or(None, |val| {
val.map(|s| from_str(&s).expect("Failed to deserialize app state")) val.map(|s| from_str(&s).expect("Failed to deserialize app state"))

View File

@ -28,7 +28,7 @@ use wasm_bindgen::throw_str;
use crate::{ use crate::{
api::{HttpStore, LocalStore}, api::{HttpStore, LocalStore},
components, components, linear::LinearSignal,
}; };
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -166,9 +166,7 @@ impl StateMachine {
original: &Signal<AppState>, original: &Signal<AppState>,
) -> Result<(), crate::api::Error> { ) -> Result<(), crate::api::Error> {
// TODO(jwall): Load plan state from local_store first. // TODO(jwall): Load plan state from local_store first.
if let Some(app_state) = local_store.fetch_app_state() { let original: LinearSignal<AppState> = original.into();
original.set_silent(app_state);
}
let mut state = original.get().as_ref().clone(); let mut state = original.get().as_ref().clone();
info!("Synchronizing Recipes"); info!("Synchronizing Recipes");
let recipe_entries = &store.fetch_recipes().await?; let recipe_entries = &store.fetch_recipes().await?;
@ -282,7 +280,7 @@ impl StateMachine {
} }
// Finally we store all of this app state back to our localstore // Finally we store all of this app state back to our localstore
local_store.store_app_state(&state); local_store.store_app_state(&state);
original.set(state); original.update(state);
Ok(()) Ok(())
} }
} }
@ -309,17 +307,15 @@ impl MessageMapper<Message, AppState> for StateMachine {
Message::RemoveExtra(idx) => { Message::RemoveExtra(idx) => {
original_copy.extras.remove(idx); original_copy.extras.remove(idx);
} }
Message::UpdateExtra(idx, amt, name) => { Message::UpdateExtra(idx, amt, name) => match original_copy.extras.get_mut(idx) {
match original_copy.extras.get_mut(idx) { Some(extra) => {
Some(extra) => { extra.0 = amt;
extra.0 = amt; extra.1 = name;
extra.1 = name;
}
None => {
throw_str("Attempted to remove extra that didn't exist");
}
} }
} None => {
throw_str("Attempted to remove extra that didn't exist");
}
},
Message::SaveRecipe(entry, callback) => { Message::SaveRecipe(entry, callback) => {
let recipe = let recipe =
parse::as_recipe(entry.recipe_text()).expect("Failed to parse RecipeEntry"); parse::as_recipe(entry.recipe_text()).expect("Failed to parse RecipeEntry");
@ -429,7 +425,8 @@ impl MessageMapper<Message, AppState> for StateMachine {
let local_store = self.local_store.clone(); let local_store = self.local_store.clone();
debug!("Loading user state."); debug!("Loading user state.");
spawn_local_scoped(cx, async move { spawn_local_scoped(cx, async move {
if let Err(err) = Self::load_state(&store, &local_store, original).await { if let Err(err) = Self::load_state(&store, &local_store, original.clone()).await
{
error!(?err, "Failed to load user state"); error!(?err, "Failed to load user state");
components::toast::error_message(cx, "Failed to load_state.", None); components::toast::error_message(cx, "Failed to load_state.", None);
} else { } else {
@ -454,7 +451,7 @@ impl MessageMapper<Message, AppState> for StateMachine {
} }
Message::SelectPlanDate(date, callback) => { Message::SelectPlanDate(date, callback) => {
let store = self.store.clone(); let store = self.store.clone();
let local_store = self.local_store.clone(); let local_store = self.local_store.clone();
spawn_local_scoped(cx, async move { spawn_local_scoped(cx, async move {
if let Some(mut plan) = store if let Some(mut plan) = store
.fetch_plan_for_date(&date) .fetch_plan_for_date(&date)
@ -491,7 +488,7 @@ impl MessageMapper<Message, AppState> for StateMachine {
} }
Message::DeletePlan(date, callback) => { Message::DeletePlan(date, callback) => {
let store = self.store.clone(); let store = self.store.clone();
let local_store = self.local_store.clone(); let local_store = self.local_store.clone();
spawn_local_scoped(cx, async move { spawn_local_scoped(cx, async move {
if let Err(err) = store.delete_plan_for_date(&date).await { if let Err(err) = store.delete_plan_for_date(&date).await {
components::toast::error_message( components::toast::error_message(

View File

@ -18,6 +18,7 @@ mod js_lib;
mod pages; mod pages;
mod routing; mod routing;
mod web; mod web;
mod linear;
use sycamore::prelude::*; use sycamore::prelude::*;
use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::prelude::wasm_bindgen;

51
web/src/linear.rs Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2022 Jeremy Wall
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::Into;
use std::ops::Drop;
use std::rc::Rc;
use sycamore::prelude::*;
pub struct LinearSignal<'ctx, Payload> {
pub signal: &'ctx Signal<Payload>,
nv: Option<Payload>,
}
impl<'ctx, Payload> Into<LinearSignal<'ctx, Payload>> for &'ctx Signal<Payload> {
fn into(self) -> LinearSignal<'ctx, Payload> {
LinearSignal { signal: self, nv: None }
}
}
impl<'ctx, Payload> LinearSignal<'ctx, Payload> {
pub fn update(mut self, payload: Payload) -> Self {
self.nv = Some(payload);
return self;
}
pub fn get(&'ctx self) -> Rc<Payload> {
self.signal.get()
}
}
impl<'ctx, Payload> Drop for LinearSignal<'ctx, Payload> {
fn drop(&mut self) {
if self.nv.is_some() {
let mut val: Option<Payload> = None;
std::mem::swap(&mut val, &mut self.nv);
let payload = val.unwrap();
self.signal.set(payload);
}
}
}