use yew::prelude::*; use crate::api; use crate::models; use crate::ui::main::{Main, MainPath}; use crate::uitools::routing::{self, Path as _}; use std::rc::Rc; #[derive(Clone, Debug)] pub struct BaseData { almanac_data: Rc>, global_data: Rc>, observers_data: Rc>, } impl BaseData { pub fn new(base: &models::Base) -> Result> { use crate::uitools::loading::{loading, load_error}; let almanac = base.almanac().get(); let global = base.global().get(); let observers = base.observers().get(); let almanac_data = if let Some(almanac_data) = almanac { if let Err(e) = &*almanac_data { return Err(load_error("almanac", || Msg::Refresh, e.as_str())); } almanac_data } else { return Err(loading("almanac")); }; let global_data = if let Some(global_data) = global { if let Err(e) = &*global_data { return Err(load_error("global", || Msg::Refresh, e.as_str())); } global_data } else { return Err(loading("global")); }; let observers_data = if let Some(observers_data) = observers { if let Err(e) = &*observers_data { return Err(load_error("observers", || Msg::Refresh, e.as_str())); } observers_data } else { return Err(loading("observers")); }; Ok(Self { almanac_data, global_data, observers_data, }) } pub fn almanac(&self) -> &api::Almanac { (*self.almanac_data).as_ref().unwrap() } pub fn global(&self) -> &api::Global { (*self.global_data).as_ref().unwrap() } pub fn observers(&self) -> &api::ObserverList { (*self.observers_data).as_ref().unwrap() } } pub enum Msg { Goto(MainPath), OnPopState(String), Refresh, Notify(()), } pub struct MainApp { base: models::Base, _base_cbr: models::CallbackRegistration, world_geo: models::WorldGeo, _world_geo_cbr: models::CallbackRegistration, _redraw_1sec: yew::services::interval::IntervalTask, path: MainPath, crumbs: Vec, } impl Component for MainApp { type Message = Msg; type Properties = (); fn create(_properties: Self::Properties, mut link: ComponentLink) -> Self { let mut interval_service = yew::services::IntervalService::new(); let onpopstate = |v: stdweb::Value| -> Msg { Msg::OnPopState(v.into_string().unwrap()) }; let onpopstate = link.send_back(onpopstate); let onpopstate = move |v| { onpopstate.emit(v) }; let pathstr = stdweb::js!{ window.onpopstate = function(event) { @{onpopstate}(window.location.hash.substr(1)); }; return window.location.hash.substr(1); }.into_string().unwrap(); let path = MainPath::parse(&pathstr); let crumbs = routing::crumbs(&path); crate::log("starting app"); let config = std::rc::Rc::new(crate::config::ConfigData { base_url: String::from("https://galmon.eu"), }); let base = models::Base::new(config.clone()); let world_geo = models::WorldGeo::new(config.clone()); Self { _base_cbr: base.register(link.send_back(Msg::Notify)), _world_geo_cbr: world_geo.register(link.send_back(Msg::Notify)), _redraw_1sec: interval_service.spawn(std::time::Duration::from_secs(/* TODO */ 100), link.send_back(|_| Msg::Notify(()))), base, world_geo, path, crumbs, } } fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { Msg::Goto(path) => { if self.path == path { false } else { self.path = path; self.crumbs = routing::crumbs(&self.path); let pathstr = routing::make_path(&self.path).unwrap(); stdweb::js!{ @(no_return) window.location = "#" + @{pathstr}; }; true } }, Msg::OnPopState(path) => { let path = MainPath::parse(&path); self.update(Msg::Goto(path)) }, Msg::Refresh => { self.base.refresh(); false }, Msg::Notify(()) => true, } } } impl MainApp { fn view_crumb(&self, crumb: &MainPath) -> Html { let crumb = crumb.clone(); let title = format!("{}", crumb); if self.path == crumb { html!{ } } else { html!{ } } } fn view_wait(&self) -> Html { match BaseData::new(&self.base) { Err(html) => html, Ok(base) => html! {
} } } } impl Renderable for MainApp { fn view(&self) -> Html { html!{
{ self.view_wait() }
} } }