commit 572516e40adb131513ed65ee7bd6be16968893cb
parent 0e30137fd49cce5487726dfde4bb1fe33a25569d
Author: Marcel <mtrnord1@gmail.com>
Date: Mon, 25 May 2020 21:30:06 +0200
Do basic setup
Took 4 hours 49 minutes
Diffstat:
14 files changed, 479 insertions(+), 348 deletions(-)
diff --git a/.idea/.gitignore b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/Daydream.iml b/.idea/Daydream.iml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
+ <excludeFolder url="file://$MODULE_DIR$/target" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module>
+\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="JavaScriptSettings">
+ <option name="languageLevel" value="ES6" />
+ </component>
+</project>
+\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/.idea/Daydream.iml" filepath="$PROJECT_DIR$/.idea/Daydream.iml" />
+ </modules>
+ </component>
+</project>
+\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsDirectoryMappings">
+ <mapping directory="" vcs="Git" />
+ </component>
+</project>
+\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
@@ -14,9 +14,14 @@ strum_macros = "0.17"
serde = "1"
serde_derive = "1"
wasm-bindgen = "0.2.58"
+wasm-bindgen-futures = "0.4.12"
wasm-logger = "0.2"
wee_alloc = { version = "0.4.4", optional = true }
-yew = "0.15"
+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"
[dev-dependencies]
wasm-bindgen-test = "0.3"
diff --git a/src/app.rs b/src/app.rs
@@ -1,358 +1,67 @@
use log::*;
use serde_derive::{Deserialize, Serialize};
-use strum::IntoEnumIterator;
-use strum_macros::{EnumIter, ToString};
-use yew::format::Json;
use yew::prelude::*;
-use yew::services::storage::{Area, StorageService};
-
-const KEY: &str = "yew.todomvc.self";
-
-pub struct App {
- link: ComponentLink<Self>,
- storage: StorageService,
- state: State,
+use yew_router::{prelude::*, Switch};
+use yew_router::switch::Permissive;
+use yew::virtual_dom::VNode;
+
+use crate::app::views::{login::Login, main_view::MainView};
+
+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>),
}
-#[derive(Serialize, Deserialize)]
-pub struct State {
- entries: Vec<Entry>,
- filter: Filter,
- value: String,
- edit_value: String,
-}
+pub struct App {}
#[derive(Serialize, Deserialize)]
-struct Entry {
- description: String,
- completed: bool,
- editing: bool,
-}
-
-pub enum Msg {
- Add,
- Edit(usize),
- Update(String),
- UpdateEdit(String),
- Remove(usize),
- SetFilter(Filter),
- ToggleAll,
- ToggleEdit(usize),
- Toggle(usize),
- ClearCompleted,
- Nope,
-}
+pub struct State {}
impl Component for App {
- type Message = Msg;
+ type Message = ();
type Properties = ();
- fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
- let storage = StorageService::new(Area::Local).unwrap();
- let entries = {
- if let Json(Ok(restored_entries)) = storage.restore(KEY) {
- restored_entries
- } else {
- Vec::new()
- }
- };
- let state = State {
- entries,
- filter: Filter::All,
- value: "".into(),
- edit_value: "".into(),
- };
- App {
- link,
- storage,
- state,
- }
+ fn create(_: Self::Properties, _link: ComponentLink<Self>) -> Self {
+ App {}
}
- fn change(&mut self, _props: Self::Properties) -> ShouldRender {
+ fn update(&mut self, _: Self::Message) -> ShouldRender {
false
}
- fn update(&mut self, msg: Self::Message) -> ShouldRender {
- match msg {
- Msg::Add => {
- let entry = Entry {
- description: self.state.value.clone(),
- completed: false,
- editing: false,
- };
- self.state.entries.push(entry);
- self.state.value = "".to_string();
- }
- Msg::Edit(idx) => {
- let edit_value = self.state.edit_value.clone();
- self.state.complete_edit(idx, edit_value);
- self.state.edit_value = "".to_string();
- }
- Msg::Update(val) => {
- println!("Input: {}", val);
- self.state.value = val;
- }
- Msg::UpdateEdit(val) => {
- println!("Input: {}", val);
- self.state.edit_value = val;
- }
- Msg::Remove(idx) => {
- self.state.remove(idx);
- }
- Msg::SetFilter(filter) => {
- self.state.filter = filter;
- }
- Msg::ToggleEdit(idx) => {
- self.state.edit_value = self.state.entries[idx].description.clone();
- self.state.toggle_edit(idx);
- }
- Msg::ToggleAll => {
- let status = !self.state.is_all_completed();
- self.state.toggle_all(status);
- }
- Msg::Toggle(idx) => {
- self.state.toggle(idx);
- }
- Msg::ClearCompleted => {
- self.state.clear_completed();
- }
- Msg::Nope => {}
- }
- self.storage.store(KEY, Json(&self.state.entries));
- true
+ fn change(&mut self, _props: Self::Properties) -> ShouldRender {
+ false
}
- fn view(&self) -> Html {
- info!("rendered!");
+ fn view(&self) -> VNode {
+ info!("rendered App!");
html! {
- <div class="todomvc-wrapper">
- <section class="todoapp">
- <header class="header">
- <h1>{ "todos" }</h1>
- { self.view_input() }
- </header>
- <section class="main">
- <input class="toggle-all" type="checkbox" checked=self.state.is_all_completed() onclick=self.link.callback(|_| Msg::ToggleAll) />
- <ul class="todo-list">
- { for self.state.entries.iter().filter(|e| self.state.filter.fit(e))
- .enumerate()
- .map(|val| self.view_entry(val)) }
- </ul>
- </section>
- <footer class="footer">
- <span class="todo-count">
- <strong>{ self.state.total() }</strong>
- { " item(s) left" }
- </span>
- <ul class="filters">
- { for Filter::iter().map(|flt| self.view_filter(flt)) }
- </ul>
- <button class="clear-completed" onclick=self.link.callback(|_| Msg::ClearCompleted)>
- { format!("Clear completed ({})", self.state.total_completed()) }
- </button>
- </footer>
- </section>
- <footer class="info">
- <p>{ "Double-click to edit a todo" }</p>
- <p>{ "Written by " }<a href="https://github.com/DenisKolodin/" target="_blank">{ "Denis Kolodin" }</a></p>
- <p>{ "Part of " }<a href="http://todomvc.com/" target="_blank">{ "TodoMVC" }</a></p>
- </footer>
+ <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)}
+ }
+ })
+ redirect = Router::redirect(|route: Route| {
+ AppRoute::PageNotFound(Permissive(Some(route.route)))
+ })
+ />
</div>
}
}
}
-
-impl App {
- fn view_filter(&self, filter: Filter) -> Html {
- let flt = filter.clone();
-
- html! {
- <li>
- <a class=if self.state.filter == flt { "selected" } else { "not-selected" }
- href=&flt
- onclick=self.link.callback(move |_| Msg::SetFilter(flt.clone()))>
- { filter }
- </a>
- </li>
- }
- }
-
- fn view_input(&self) -> Html {
- html! {
- // You can use standard Rust comments. One line:
- // <li></li>
- <input class="new-todo"
- placeholder="What needs to be done?"
- value=&self.state.value
- oninput=self.link.callback(|e: InputData| Msg::Update(e.value))
- onkeypress=self.link.callback(|e: KeyboardEvent| {
- if e.key() == "Enter" { Msg::Add } else { Msg::Nope }
- }) />
- /* Or multiline:
- <ul>
- <li></li>
- </ul>
- */
- }
- }
-
- fn view_entry(&self, (idx, entry): (usize, &Entry)) -> Html {
- let mut class = "todo".to_string();
- if entry.editing {
- class.push_str(" editing");
- }
- if entry.completed {
- class.push_str(" completed");
- }
-
- html! {
- <li class=class>
- <div class="view">
- <input class="toggle" type="checkbox" checked=entry.completed onclick=self.link.callback(move |_| Msg::Toggle(idx)) />
- <label ondoubleclick=self.link.callback(move |_| Msg::ToggleEdit(idx))>{ &entry.description }</label>
- <button class="destroy" onclick=self.link.callback(move |_| Msg::Remove(idx)) />
- </div>
- { self.view_entry_edit_input((&idx, &entry)) }
- </li>
- }
- }
-
- fn view_entry_edit_input(&self, (idx, entry): (&usize, &Entry)) -> Html {
- let idx = *idx;
- if entry.editing {
- html! {
- <input class="edit"
- type="text"
- value=&entry.description
- oninput=self.link.callback(move |e: InputData| Msg::UpdateEdit(e.value))
- onblur=self.link.callback(move |_| Msg::Edit(idx))
- onkeypress=self.link.callback(move |e: KeyboardEvent| {
- if e.key() == "Enter" { Msg::Edit(idx) } else { Msg::Nope }
- }) />
- }
- } else {
- html! { <input type="hidden" /> }
- }
- }
-}
-
-#[derive(EnumIter, ToString, Clone, PartialEq, Serialize, Deserialize)]
-pub enum Filter {
- All,
- Active,
- Completed,
-}
-
-impl<'a> Into<Href> for &'a Filter {
- fn into(self) -> Href {
- match *self {
- Filter::All => "#/".into(),
- Filter::Active => "#/active".into(),
- Filter::Completed => "#/completed".into(),
- }
- }
-}
-
-impl Filter {
- fn fit(&self, entry: &Entry) -> bool {
- match *self {
- Filter::All => true,
- Filter::Active => !entry.completed,
- Filter::Completed => entry.completed,
- }
- }
-}
-
-impl State {
- fn total(&self) -> usize {
- self.entries.len()
- }
-
- fn total_completed(&self) -> usize {
- self.entries
- .iter()
- .filter(|e| Filter::Completed.fit(e))
- .count()
- }
-
- fn is_all_completed(&self) -> bool {
- let mut filtered_iter = self
- .entries
- .iter()
- .filter(|e| self.filter.fit(e))
- .peekable();
-
- if filtered_iter.peek().is_none() {
- return false;
- }
-
- filtered_iter.all(|e| e.completed)
- }
-
- fn toggle_all(&mut self, value: bool) {
- for entry in self.entries.iter_mut() {
- if self.filter.fit(entry) {
- entry.completed = value;
- }
- }
- }
-
- fn clear_completed(&mut self) {
- let entries = self
- .entries
- .drain(..)
- .filter(|e| Filter::Active.fit(e))
- .collect();
- self.entries = entries;
- }
-
- fn toggle(&mut self, idx: usize) {
- let filter = self.filter.clone();
- let mut entries = self
- .entries
- .iter_mut()
- .filter(|e| filter.fit(e))
- .collect::<Vec<_>>();
- let entry = entries.get_mut(idx).unwrap();
- entry.completed = !entry.completed;
- }
-
- fn toggle_edit(&mut self, idx: usize) {
- let filter = self.filter.clone();
- let mut entries = self
- .entries
- .iter_mut()
- .filter(|e| filter.fit(e))
- .collect::<Vec<_>>();
- let entry = entries.get_mut(idx).unwrap();
- entry.editing = !entry.editing;
- }
-
- fn complete_edit(&mut self, idx: usize, val: String) {
- let filter = self.filter.clone();
- let mut entries = self
- .entries
- .iter_mut()
- .filter(|e| filter.fit(e))
- .collect::<Vec<_>>();
- let entry = entries.get_mut(idx).unwrap();
- entry.description = val;
- entry.editing = !entry.editing;
- }
-
- fn remove(&mut self, idx: usize) {
- let idx = {
- let filter = self.filter.clone();
- let entries = self
- .entries
- .iter()
- .enumerate()
- .filter(|&(_, e)| filter.fit(e))
- .collect::<Vec<_>>();
- let &(idx, _) = entries.get(idx).unwrap();
- idx
- };
- self.entries.remove(idx);
- }
-}
diff --git a/src/app/matrix.rs b/src/app/matrix.rs
@@ -0,0 +1,168 @@
+use log::*;
+use matrix_sdk::{Client, ClientConfig};
+use serde_derive::{Deserialize, Serialize};
+use std::collections::HashSet;
+use url::Url;
+use wasm_bindgen_futures::spawn_local;
+use yew::worker::*;
+
+#[derive(Serialize, Deserialize, Default, Clone)]
+pub struct MatrixClient {
+ pub(crate) homeserver: Option<String>,
+ pub(crate) username: Option<String>,
+ pub(crate) password: Option<String>,
+}
+
+#[derive(Clone)]
+pub struct MatrixAgent {
+ link: AgentLink<MatrixAgent>,
+ matrix_state: MatrixClient,
+ matrix_client: Option<Client>,
+ subscribers: HashSet<HandlerId>,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub enum Request {
+ SetHomeserver(String),
+ SetUsername(String),
+ SetPassword(String),
+ Login(),
+ GetLoggedIn,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct Response {
+ pub message: String,
+ pub content: String,
+}
+
+impl Agent for MatrixAgent {
+ type Reach = Context;
+ type Message = ();
+ type Input = Request;
+ type Output = Response;
+
+ fn create(link: AgentLink<Self>) -> Self {
+ MatrixAgent {
+ link,
+ matrix_state: Default::default(),
+ matrix_client: None,
+ subscribers: HashSet::new(),
+ }
+ }
+
+ fn update(&mut self, _: Self::Message) {}
+
+ fn handle_input(&mut self, msg: Self::Input, _: HandlerId) {
+ match msg {
+ Request::SetHomeserver(homeserver) => {
+ self.matrix_state.homeserver = Some(homeserver.clone());
+ }
+ Request::SetUsername(username) => {
+ self.matrix_state.username = Some(username.clone());
+ }
+ Request::SetPassword(password) => {
+ self.matrix_state.password = Some(password.clone());
+ }
+ Request::Login() => {
+ let login_client = self.login();
+ if login_client.is_none() {
+ let resp = Response {
+ message: "login_missing_client".to_string(),
+ content: "".to_string(),
+ };
+ for sub in self.subscribers.iter() {
+ self.link.respond(*sub, resp.clone());
+ }
+ return;
+ }
+ let client = login_client.clone().unwrap();
+ let username = self.matrix_state.username.clone().unwrap();
+ let password = self.matrix_state.password.clone().unwrap();
+ let username = username.clone();
+ let password = password.clone();
+ let client = client.clone();
+ let subscribers = self.subscribers.clone();
+ let agent = self.clone();
+ spawn_local(async move {
+ client
+ .login(
+ username.clone(),
+ password.clone(),
+ None,
+ Some("Daydream".to_string()),
+ )
+ .await;
+ info!("did login");
+ let resp = Response {
+ message: "login_logged_in".to_string(),
+ content: "".to_string(),
+ };
+ info!("prepared login response");
+ for sub in subscribers.iter() {
+ agent.link.respond(*sub, resp.clone());
+ }
+ info!("sent login response");
+ });
+ }
+ Request::GetLoggedIn => {
+ let subscribers = self.subscribers.clone();
+ let agent = self.clone();
+ spawn_local(async move {
+ let logged_in = agent.get_logged_in().await;
+ let resp = Response {
+ message: "client_logged_in".to_string(),
+ content: logged_in,
+ };
+ for sub in subscribers.iter() {
+ agent.link.respond(*sub, resp.clone());
+ }
+ });
+ }
+ }
+ }
+ fn connected(&mut self, id: HandlerId) {
+ self.subscribers.insert(id);
+ }
+
+ fn disconnected(&mut self, id: HandlerId) {
+ self.subscribers.remove(&id);
+ }
+}
+
+impl MatrixAgent {
+ async fn get_logged_in(&self) -> String {
+ self.matrix_client
+ .clone()
+ .unwrap()
+ .logged_in()
+ .await
+ .to_string()
+ }
+
+ fn login(&mut self) -> Option<Client> {
+ return if self.matrix_state.homeserver.is_none()
+ || self.matrix_state.username.is_none()
+ || self.matrix_state.password.is_none()
+ || self.matrix_client.is_some()
+ {
+ let resp = Response {
+ message: "login_fields_missing".to_string(),
+ content: "".to_string(),
+ };
+ for sub in self.subscribers.iter() {
+ self.link.respond(*sub, resp.clone());
+ }
+ None
+ } else {
+ let homeserver = self.matrix_state.homeserver.clone().unwrap();
+
+ let client_config = ClientConfig::new();
+ let homeserver_url = Url::parse(&homeserver.clone()).unwrap();
+ let client = Client::new_with_config(homeserver_url, client_config).unwrap();
+ self.matrix_client = Some(client.clone());
+
+ Some(client.clone())
+ };
+ }
+}
diff --git a/src/app/views/login.rs b/src/app/views/login.rs
@@ -0,0 +1,140 @@
+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::*;
+
+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 {
+ SetHomeserver(String),
+ 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,
+ homeserver: "".to_string(),
+ username: "".to_string(),
+ password: "".to_string(),
+ storage,
+ matrix_agent,
+ _producer,
+ }
+ }
+
+ fn update(&mut self, msg: Self::Message) -> ShouldRender {
+ match msg {
+ Msg::SetHomeserver(homeserver) => {
+ self.homeserver = homeserver.clone();
+ self.matrix_agent
+ .send(Request::SetHomeserver(homeserver.clone()));
+ true
+ }
+ Msg::SetUsername(username) => {
+ self.username = username.clone();
+ self.matrix_agent
+ .send(Request::SetUsername(username.clone()));
+ true
+ }
+ Msg::SetPassword(password) => {
+ self.password = password.clone();
+ self.matrix_agent
+ .send(Request::SetPassword(password.clone()));
+ true
+ }
+ 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
+ }
+ 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
+ }
+ }
+ }
+
+ fn change(&mut self, _props: Self::Properties) -> ShouldRender {
+ false
+ }
+
+ fn view(&self) -> Html {
+ info!("rendered App!");
+ html! {
+ <div>
+ <input class="server"
+ placeholder="Homeserver URL"
+ value=&self.homeserver
+ oninput=self.link.callback(|e: InputData| Msg::SetHomeserver(e.value))
+ //onkeypress=self.link.callback(|e: KeyboardEvent| {
+ // if e.key() == "Enter" { Msg::Add } else { Msg::Nope }
+ //})
+ />
+ <input class="username"
+ placeholder="MXID/Username"
+ value=&self.username
+ oninput=self.link.callback(|e: InputData| Msg::SetUsername(e.value))
+ //onkeypress=self.link.callback(|e: KeyboardEvent| {
+ // if e.key() == "Enter" { Msg::Add } else { Msg::Nope }
+ //})
+ />
+ <input class="password"
+ placeholder="Password"
+ 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)>
+ { "Login" }
+ </button>
+ </div>
+ }
+ }
+}
diff --git a/src/app/views/main_view.rs b/src/app/views/main_view.rs
@@ -0,0 +1,68 @@
+use log::*;
+use serde_derive::{Deserialize, Serialize};
+use yew::agent::{Dispatched, Dispatcher};
+use yew::prelude::*;
+use yew::services::storage::Area;
+use yew::services::StorageService;
+use yew::ComponentLink;
+
+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>>,
+}
+
+pub enum Msg {
+ NewMessage(Response),
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct State {}
+
+impl Component for MainView {
+ type Message = Msg;
+ type Properties = ();
+
+ 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 state = State {};
+
+ MainView {
+ link,
+ storage,
+ matrix_agent,
+ state,
+ _producer,
+ }
+ }
+
+ fn update(&mut self, msg: Self::Message) -> bool {
+ match msg {
+ Msg::NewMessage(response) => {
+ info!("NewMessage: {:#?}", response);
+ if response.message == "client_logged_in" {
+ info!("client_logged_in: {}", response.content);
+ }
+ }
+ }
+ true
+ }
+
+ fn change(&mut self, _props: Self::Properties) -> bool {
+ false
+ }
+
+ fn view(&self) -> Html {
+ info!("rendered MainView!");
+ html! {
+ <p>{"Test"}</p>
+ }
+ }
+}
diff --git a/src/app/views/mod.rs b/src/app/views/mod.rs
@@ -0,0 +1,2 @@
+pub mod login;
+pub mod main_view;
diff --git a/static/index.html b/static/index.html
@@ -2,11 +2,9 @@
<html lang="en">
<head>
<meta charset="utf-8" />
- <title>Yew • TodoMVC</title>
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/todomvc-common@1.0.5/base.css"/ >
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/todomvc-app-css@2.1.2/index.css" />
+ <title>Daydream</title>
</head>
<body>
- <script src="/todomvc.js"></script>
+ <script src="/daydream.js"></script>
</body>
</html>
diff --git a/static/style.scss b/static/style.scss
@@ -1,5 +0,0 @@
-$background: #f5f5f5;
-
-body {
- background: $background;
-}
diff --git a/webpack.config.js b/webpack.config.js
@@ -8,13 +8,14 @@ module.exports = (env, argv) => {
devServer: {
contentBase: distPath,
compress: argv.mode === 'production',
- port: 8000
+ port: 8000,
+ historyApiFallback: true
},
entry: './bootstrap.js',
output: {
path: distPath,
- filename: "todomvc.js",
- webassemblyModuleFilename: "todomvc.wasm"
+ filename: "daydream.js",
+ webassemblyModuleFilename: "daydream.wasm"
},
module: {
rules: [