app: Swap to using dioxus instead of yew
This commit is contained in:
parent
02a4187c39
commit
c80cc99255
29 changed files with 3558 additions and 3639 deletions
189
app/src/full_context.rs
Normal file
189
app/src/full_context.rs
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
use std::{
|
||||
cell::{Cell, Ref, RefCell},
|
||||
collections::HashSet,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::use_router;
|
||||
use gloo_storage::{errors::StorageError, LocalStorage, Storage};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{HouseholdInfo, LoginInfo, RedirectorProps};
|
||||
|
||||
pub struct RefreshHandle {
|
||||
run: Box<dyn FnOnce()>,
|
||||
}
|
||||
|
||||
impl RefreshHandle {
|
||||
pub fn refresh(self) {
|
||||
(self.run)()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FullContextState<'a> {
|
||||
root: &'a ProvidedFullContext,
|
||||
value: &'a Rc<RefCell<FullContext>>,
|
||||
}
|
||||
|
||||
impl<'a> FullContextState<'a> {
|
||||
pub fn read(&self) -> Ref<'_, FullContext> {
|
||||
self.value.borrow()
|
||||
}
|
||||
|
||||
pub fn refresh(&self) {
|
||||
let r = self.root.borrow();
|
||||
|
||||
r.needs_regen.set(true);
|
||||
(r.update_root)();
|
||||
}
|
||||
|
||||
pub fn refresh_handle(&self) -> RefreshHandle {
|
||||
let r = self.root.clone();
|
||||
RefreshHandle {
|
||||
run: Box::new(move || {
|
||||
let root = r.borrow();
|
||||
root.needs_regen.set(true);
|
||||
(root.update_root)();
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FullContextStateInner {
|
||||
root: ProvidedFullContext,
|
||||
value: Rc<RefCell<FullContext>>,
|
||||
scope_id: ScopeId,
|
||||
}
|
||||
|
||||
impl Drop for FullContextStateInner {
|
||||
fn drop(&mut self) {
|
||||
let mut root = self.root.borrow_mut();
|
||||
root.consumers.remove(&self.scope_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_full_context(cx: &ScopeState) -> FullContextState {
|
||||
let state = cx.use_hook(|| {
|
||||
let scope_id = cx.scope_id();
|
||||
let root = cx
|
||||
.consume_context::<ProvidedFullContext>()
|
||||
.expect("Called use_full_context not in a full context scope");
|
||||
|
||||
let mut r = root.borrow_mut();
|
||||
|
||||
r.consumers.insert(scope_id);
|
||||
let value = r.value.clone();
|
||||
|
||||
drop(r);
|
||||
FullContextStateInner {
|
||||
root,
|
||||
value,
|
||||
scope_id,
|
||||
}
|
||||
});
|
||||
|
||||
FullContextState {
|
||||
root: &state.root,
|
||||
value: &state.value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_trimmed_context(cx: &ScopeState) -> (String, Uuid) {
|
||||
let binding = use_full_context(cx);
|
||||
let ctx = binding.read();
|
||||
|
||||
(ctx.login.token.clone(), ctx.household.id)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FullContext {
|
||||
pub login: LoginInfo,
|
||||
pub household: HouseholdInfo,
|
||||
}
|
||||
|
||||
type ProvidedFullContext = Rc<RefCell<ProvidedFullContextInner>>;
|
||||
|
||||
struct ProvidedFullContextInner {
|
||||
value: Rc<RefCell<FullContext>>,
|
||||
notify_any: Arc<dyn Fn(ScopeId)>,
|
||||
consumers: HashSet<ScopeId>,
|
||||
needs_regen: Cell<bool>,
|
||||
update_root: Arc<dyn Fn()>,
|
||||
}
|
||||
|
||||
impl ProvidedFullContextInner {
|
||||
fn notify_consumers(&mut self) {
|
||||
for &consumer in &self.consumers {
|
||||
(self.notify_any)(consumer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn use_full_context_setter(cx: &ScopeState) {
|
||||
let gen = || {
|
||||
let login = LocalStorage::get::<LoginInfo>("token").expect("Not called in a full context");
|
||||
let household =
|
||||
LocalStorage::get::<HouseholdInfo>("household").expect("Not called in a full context");
|
||||
|
||||
FullContext { login, household }
|
||||
};
|
||||
|
||||
let hook = cx.use_hook(move || {
|
||||
let state = Rc::new(RefCell::new(ProvidedFullContextInner {
|
||||
value: Rc::new(RefCell::new(gen())),
|
||||
consumers: HashSet::new(),
|
||||
notify_any: cx.schedule_update_any(),
|
||||
update_root: cx.schedule_update(),
|
||||
needs_regen: Cell::new(false),
|
||||
}));
|
||||
|
||||
cx.provide_context(state.clone());
|
||||
|
||||
state
|
||||
});
|
||||
|
||||
if hook.borrow().needs_regen.get() {
|
||||
let mut hook = (**hook).borrow_mut();
|
||||
*(*hook.value).borrow_mut() = gen();
|
||||
hook.notify_consumers();
|
||||
}
|
||||
}
|
||||
|
||||
fn FullContextRedirectInner<'a>(cx: Scope<'a, RedirectorProps<'a>>) -> Element {
|
||||
use_full_context_setter(cx);
|
||||
|
||||
cx.render(rsx! {&cx.props.children})
|
||||
}
|
||||
|
||||
pub fn FullContextRedirect<'a>(cx: Scope<'a, RedirectorProps<'a>>) -> Element {
|
||||
let router = use_router(cx);
|
||||
|
||||
let check_token = match LocalStorage::get::<LoginInfo>("token") {
|
||||
Ok(_) => true,
|
||||
Err(StorageError::KeyNotFound(_)) => {
|
||||
router.navigate_to("/login");
|
||||
false
|
||||
}
|
||||
Err(e) => unreachable!("Could not get token: {e:?}"),
|
||||
};
|
||||
|
||||
let check_household = match LocalStorage::get::<HouseholdInfo>("household") {
|
||||
Ok(_) => true,
|
||||
Err(StorageError::KeyNotFound(_)) => {
|
||||
router.navigate_to("/household_selection");
|
||||
false
|
||||
}
|
||||
Err(e) => unreachable!("Could not get household: {e:?}"),
|
||||
};
|
||||
|
||||
if check_token && check_household {
|
||||
cx.render(rsx! {
|
||||
FullContextRedirectInner { &cx.props.children }
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue