daydream

A small matrix web client written in rust
git clone git://archive.git.mtrnord.blog/daydream-mx/daydream.git
Log | Files | Refs | README | LICENSE

commit bb4a25c3e064e56b780785c7bdd9d8c7edd07955
parent 572516e40adb131513ed65ee7bd6be16968893cb
Author: Marcel <mtrnord1@gmail.com>
Date:   Tue, 26 May 2020 13:39:24 +0200

Fix routing

Took 1 hour 31 minutes

Diffstat:
MCargo.toml | 9++++++---
Msrc/app.rs | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/app/matrix.rs | 8++++++--
Msrc/app/views/login.rs | 46+++++++++-------------------------------------
Msrc/app/views/main_view.rs | 8++------
Msrc/lib.rs | 33++++++++++++++++++++++++++++-----
6 files changed, 140 insertions(+), 87 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -8,26 +8,29 @@ edition = "2018" crate-type = ["cdylib", "rlib"] [dependencies] +cfg-if = "0.1" +console_error_panic_hook = { version = "0.1", optional = true } log = "0.4" strum = "0.17" strum_macros = "0.17" serde = "1" serde_derive = "1" -wasm-bindgen = "0.2.58" +wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4.12" wasm-logger = "0.2" -wee_alloc = { version = "0.4.4", optional = true } +wee_alloc = "0.4" yew = "0.16" yew-router = "0.13" futures = "0.3" matrix-sdk = { version = "0.1.0", git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false} url = "2.1.1" +yew_styles = "0.3.1" [dev-dependencies] wasm-bindgen-test = "0.3" [dependencies.web-sys] -version = "0.3.4" +version = "0.3" features = [ 'KeyboardEvent', ] diff --git a/src/app.rs b/src/app.rs @@ -1,66 +1,121 @@ use log::*; -use serde_derive::{Deserialize, Serialize}; -use yew::prelude::*; +use yew::{prelude::*, virtual_dom::VNode}; use yew_router::{prelude::*, Switch}; -use yew_router::switch::Permissive; -use yew::virtual_dom::VNode; use crate::app::views::{login::Login, main_view::MainView}; +use crate::app::matrix::{Response, MatrixAgent}; +use yew_router::agent::RouteRequest::ChangeRoute; mod matrix; mod views; #[derive(Switch, Clone)] pub enum AppRoute { - #[to = "/"] - Start, - #[to = "/login"] - Login, #[to = "/app"] MainView, - #[to = "/page-not-found"] - PageNotFound(Permissive<String>), + #[to = "/"] + Start, +} +pub enum Msg { + RouteChanged(Route<()>), + ChangeRoute(AppRoute), + NewMessage(Response), +} +pub struct App { + matrix_agent: Box<dyn Bridge<MatrixAgent>>, + link: ComponentLink<Self>, + route: Option<Route<()>>, + route_agent: Box<dyn Bridge<RouteAgent<()>>>, } -pub struct App {} - -#[derive(Serialize, Deserialize)] -pub struct State {} - +impl App { + fn change_route(&self, app_route: AppRoute) -> Callback<MouseEvent> { + self.link.callback(move |_| { + let route = app_route.clone(); + Msg::ChangeRoute(route) + }) + } +} impl Component for App { - type Message = (); + type Message = Msg; type Properties = (); - fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self { - App {} + fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { + let route_agent = RouteAgent::bridge(link.callback(Msg::RouteChanged)); + let mut matrix_agent = MatrixAgent::bridge(link.callback(Msg::NewMessage)); + matrix_agent.send(matrix::Request::GetLoggedIn); + App { + matrix_agent, + route_agent, + route: None, + link, + } } - fn update(&mut self, _: Self::Message) -> ShouldRender { - false + fn update(&mut self, msg: Self::Message) -> ShouldRender { + match msg { + Msg::RouteChanged(route) => { + self.route = Some(route); + } + Msg::ChangeRoute(route) => { + let route: Route = route.into(); + self.route = Some(route.clone()); + self.route_agent.send(ChangeRoute(route)); + } + Msg::NewMessage(response) => { + info!("NewMessage: {:#?}", response); + if response.message == "client_logged_in"{ + info!("client_logged_in"); + info!("{}", response.content); + let route: Route = if response.content == "true" { + //self.state.logged_in = true; + + // replace with sync routeagent message once its possible + // https://github.com/yewstack/yew/issues/1127 + //RouteService::new().get_route(); + AppRoute::MainView.into() + } else { + AppRoute::Start.into() + }; + + info!("{:#?}", route.clone()); + self.route = Some(route.clone()); + self.route_agent.send(ChangeRoute(route)); + } + } + } + true } fn change(&mut self, _props: Self::Properties) -> ShouldRender { false } - fn view(&self) -> VNode { + fn view(&self) -> Html { info!("rendered App!"); + info!("Route: {:#?}", &self.route); html! { <div> - <Router<AppRoute, ()> - render = Router::render(|switch: AppRoute| { - match switch { - AppRoute::Start => html!{<Login />}, - AppRoute::Login => html!{<Login />}, - AppRoute::MainView => html!{<MainView />}, - AppRoute::PageNotFound(Permissive(None)) => html!{"Page not found"}, - AppRoute::PageNotFound(Permissive(Some(missed_route))) => html!{format!("Page '{}' not found", missed_route)} + { + match &self.route { + None => {info!("NoneRoute"); html! {<Login />}}, + Some(route) => match AppRoute::switch(route.clone()) { + Some(AppRoute::MainView) => { + info!("MainViewRoute"); + html! { + <MainView /> + } + }, + Some(AppRoute::Start) => { + info!("StartRoute"); + html! { + <Login /> + } + }, + None => VNode::from("404") } - }) - redirect = Router::redirect(|route: Route| { - AppRoute::PageNotFound(Permissive(Some(route.route))) - }) - /> + } + } </div> } } diff --git a/src/app/matrix.rs b/src/app/matrix.rs @@ -30,6 +30,7 @@ pub enum Request { GetLoggedIn, } +// TODO make enum #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Response { pub message: String, @@ -95,8 +96,8 @@ impl Agent for MatrixAgent { .await; info!("did login"); let resp = Response { - message: "login_logged_in".to_string(), - content: "".to_string(), + message: "client_logged_in".to_string(), + content: "true".to_string(), }; info!("prepared login response"); for sub in subscribers.iter() { @@ -132,6 +133,9 @@ impl Agent for MatrixAgent { impl MatrixAgent { async fn get_logged_in(&self) -> String { + if self.matrix_client.is_none() { + return "false".to_string(); + } self.matrix_client .clone() .unwrap() diff --git a/src/app/views/login.rs b/src/app/views/login.rs @@ -1,23 +1,17 @@ use log::*; -use serde_derive::{Deserialize, Serialize}; use yew::agent::{Dispatched, Dispatcher}; use yew::prelude::*; use yew::services::storage::{Area, StorageService}; -use yew_router::{route::Route}; -use crate::app::matrix::{MatrixAgent, Request, Response}; -use yew_router::agent::RouteRequest; -use yew_router::prelude::*; +use crate::app::matrix::{MatrixAgent, Request}; pub struct Login { link: ComponentLink<Self>, - router: Box<dyn Bridge<RouteAgent>>, homeserver: String, username: String, password: String, storage: StorageService, matrix_agent: Dispatcher<MatrixAgent>, - _producer: Box<dyn Bridge<MatrixAgent>>, } pub enum Msg { @@ -25,32 +19,25 @@ pub enum Msg { SetUsername(String), SetPassword(String), Login, - Navigate(String), - NewMessage(Response), Nope, } + impl Component for Login { type Message = Msg; type Properties = (); fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { - let callback = link.callback(|_| Msg::Nope); // TODO use a dispatcher instead. - let router = RouteAgent::bridge(callback); - let storage = StorageService::new(Area::Local).unwrap(); let matrix_agent = MatrixAgent::dispatcher(); - let matrix_callback = link.callback(Msg::NewMessage); - let _producer = MatrixAgent::bridge(matrix_callback); Login { link, - router, + //TODO use state homeserver: "".to_string(), username: "".to_string(), password: "".to_string(), storage, matrix_agent, - _producer, } } @@ -77,24 +64,9 @@ impl Component for Login { Msg::Login => { info!("Start Login"); self.matrix_agent.send(Request::Login()); - true - } - Msg::Navigate(route_string) => { - let route = Route::from(route_string); - - self.router.send(RouteRequest::ChangeRoute(route)); - true + false } Msg::Nope => false, - Msg::NewMessage(response) => { - info!("NewMessage: {:#?}", response); - if response.message == "login_logged_in" { - info!("Finished Login"); - self.link - .callback(|_: InputData| Msg::Navigate("/app".to_owned())); - } - true - } } } @@ -103,7 +75,7 @@ impl Component for Login { } fn view(&self) -> Html { - info!("rendered App!"); + info!("rendered Login!"); html! { <div> <input class="server" @@ -127,11 +99,11 @@ impl Component for Login { type="password" value=&self.password oninput=self.link.callback(|e: InputData| Msg::SetPassword(e.value)) - //onkeypress=self.link.callback(|e: KeyboardEvent| { - // if e.key() == "Enter" { Msg::Add } else { Msg::Nope } - //}) /> - <button onclick=self.link.callback(|_: MouseEvent| Msg::Login)> + <button onclick=self.link.callback(|_: MouseEvent| Msg::Login) + onkeypress=self.link.callback(|e: KeyboardEvent| { + if e.key() == "Enter" { Msg::Login } else { Msg::Nope } + })> { "Login" } </button> </div> diff --git a/src/app/views/main_view.rs b/src/app/views/main_view.rs @@ -1,6 +1,5 @@ use log::*; use serde_derive::{Deserialize, Serialize}; -use yew::agent::{Dispatched, Dispatcher}; use yew::prelude::*; use yew::services::storage::Area; use yew::services::StorageService; @@ -11,9 +10,8 @@ use crate::app::matrix::{MatrixAgent, Response}; pub struct MainView { link: ComponentLink<Self>, storage: StorageService, - matrix_agent: Dispatcher<MatrixAgent>, state: State, - _producer: Box<dyn Bridge<MatrixAgent>>, + matrix_agent: Box<dyn Bridge<MatrixAgent>>, } pub enum Msg { @@ -29,9 +27,8 @@ impl Component for MainView { fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { let storage = StorageService::new(Area::Local).unwrap(); - let matrix_agent = MatrixAgent::dispatcher(); let matrix_callback = link.callback(Msg::NewMessage); - let _producer = MatrixAgent::bridge(matrix_callback); + let matrix_agent = MatrixAgent::bridge(matrix_callback); let state = State {}; MainView { @@ -39,7 +36,6 @@ impl Component for MainView { storage, matrix_agent, state, - _producer, } } diff --git a/src/lib.rs b/src/lib.rs @@ -1,18 +1,41 @@ + #![recursion_limit = "512"] +#[macro_use] +extern crate cfg_if; mod app; use wasm_bindgen::prelude::*; -// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global -// allocator. -#[cfg(feature = "wee_alloc")] -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; +cfg_if! { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function to get better error messages if we ever panic. + if #[cfg(feature = "console_error_panic_hook")] { + extern crate console_error_panic_hook; + use console_error_panic_hook::set_once as set_panic_hook; + } else { + #[inline] + fn set_panic_hook() {} + } +} + +cfg_if! { + // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global + // allocator. + if #[cfg(feature = "wee_alloc")] { + extern crate wee_alloc; + #[global_allocator] + static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + } +} + // This is the entry point for the web app #[wasm_bindgen] pub fn run_app() -> Result<(), JsValue> { + // If the `console_error_panic_hook` feature is enabled this will set a panic hook, otherwise + // it will do nothing. + set_panic_hook(); wasm_logger::init(wasm_logger::Config::default()); yew::start_app::<app::App>(); Ok(())