commit 447a0461183cc5a46823adf37d6f69c7b0140401
parent 6c92e489db2b9a75ed1668ae2d6e2f7ee3193c6a
Author: Marcel <mtrnord1@gmail.com>
Date: Wed, 27 May 2020 00:59:09 +0200
Switch Css framework and add basics of rooms
Took 5 hours 7 minutes
Diffstat:
12 files changed, 246 insertions(+), 102 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -16,8 +16,8 @@ console_error_panic_hook = { version = "0.1", optional = true }
log = "0.4"
strum = "0.17"
strum_macros = "0.17"
-serde = "1"
-serde_derive = "1"
+serde = { version = "1.0", features = ["rc", "derive"] }
+serde_json = "1.0.53"
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4.12"
wasm-logger = "0.2"
@@ -29,6 +29,7 @@ matrix-sdk = { version = "0.1.0", git = "https://github.com/matrix-org/matrix-ru
url = "2.1.1"
yew_styles = "0.3.1"
thiserror = "1.0"
+futures-locks = { git = "https://github.com/asomers/futures-locks", default-features = false }
[dev-dependencies]
wasm-bindgen-test = "0.3"
diff --git a/package.json b/package.json
@@ -19,6 +19,6 @@
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
- "bootstrap": "^4.5.0"
+ "uikit": "^3.4.6"
}
}
diff --git a/src/app/matrix.rs b/src/app/matrix.rs
@@ -1,10 +1,11 @@
-use std::collections::HashSet;
+use std::collections::{HashSet, HashMap};
use std::convert::TryFrom;
use std::sync::{Arc, Mutex};
+use std::sync::RwLock as SyncRwLock;
use log::*;
-use matrix_sdk::{Client, ClientConfig, Session, SyncSettings};
-use serde_derive::{Deserialize, Serialize};
+use matrix_sdk::{Client, ClientConfig, Session, SyncSettings, Room, identifiers::RoomId};
+use serde::{Deserialize, Serialize};
use url::Url;
use wasm_bindgen_futures::spawn_local;
use yew::format::Json;
@@ -13,8 +14,12 @@ use yew::worker::*;
use crate::constants::AUTH_KEY;
use crate::errors::MatrixError;
+use futures_locks::RwLock;
+use crate::app::matrix::types::{SmallRoom, MessageWrapper};
+use yew_styles::button::Size::Small;
mod sync;
+pub mod types;
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct MatrixClient {
@@ -25,10 +30,10 @@ pub struct MatrixClient {
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct SessionStore {
- access_token: String,
- user_id: String,
- device_id: String,
- homeserver_url: String,
+ pub(crate) access_token: String,
+ pub(crate) user_id: String,
+ pub(crate) device_id: String,
+ pub(crate) homeserver_url: String,
}
#[derive(Clone, Debug)]
@@ -50,6 +55,7 @@ pub enum Request {
Login(),
GetLoggedIn,
StartSync,
+ GetJoinedRooms,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -57,7 +63,9 @@ pub enum Response {
Error(MatrixError),
LoggedIn(bool),
// TODO properly handle sync events
- Sync(String),
+ Sync(MessageWrapper),
+ FinishedFirstSync,
+ JoinedRoomList(HashMap<RoomId, SmallRoom>),
}
impl Agent for MatrixAgent {
@@ -106,9 +114,9 @@ impl Agent for MatrixAgent {
Request::Login() => {
let login_client = self.login();
if login_client.is_none() {
- let resp = Response::Error(MatrixError::MissingClient);
for sub in self.subscribers.iter() {
- self.link.respond(*sub, resp.clone());
+ let resp = Response::Error(MatrixError::MissingClient);
+ self.link.respond(*sub, resp);
}
return;
}
@@ -129,7 +137,7 @@ impl Agent for MatrixAgent {
user_id: matrix_sdk::identifiers::UserId::try_from(
stored_session.user_id.as_str(),
)
- .unwrap(),
+ .unwrap(),
device_id: stored_session.device_id,
};
client.restore_login(session).await;
@@ -153,9 +161,9 @@ impl Agent for MatrixAgent {
storage.store(AUTH_KEY, Json(&session_store));
}
- let resp = Response::LoggedIn(true);
for sub in subscribers.iter() {
- agent.link.respond(*sub, resp.clone());
+ let resp = Response::LoggedIn(true);
+ agent.link.respond(*sub, resp);
}
});
}
@@ -163,9 +171,9 @@ impl Agent for MatrixAgent {
let subscribers = self.subscribers.clone();
let login_client = self.login();
if login_client.is_none() {
- let resp = Response::Error(MatrixError::MissingClient);
for sub in self.subscribers.iter() {
- self.link.respond(*sub, resp.clone());
+ let resp = Response::Error(MatrixError::MissingClient);
+ self.link.respond(*sub, resp);
}
return;
}
@@ -179,9 +187,9 @@ impl Agent for MatrixAgent {
if !logged_in && agent.session.is_some() {
error!("Not logged in but got session");
} else {
- let resp = Response::LoggedIn(logged_in.clone());
for sub in subscribers.iter() {
- agent.link.respond(*sub, resp.clone());
+ let resp = Response::LoggedIn(logged_in.clone());
+ agent.link.respond(*sub, resp);
}
}
});
@@ -193,6 +201,26 @@ impl Agent for MatrixAgent {
agent.start_sync().await;
});
}
+ Request::GetJoinedRooms => {
+ let agent = self.clone();
+ let client = agent.matrix_client.clone().unwrap();
+ spawn_local(async move {
+ for sub in agent.subscribers.iter() {
+ let rooms: Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>> = client.clone().joined_rooms();
+ let mut rooms_list_hack = HashMap::new();
+ for (id, room) in rooms.read().await.iter() {
+ let small_room = SmallRoom {
+ name: room.read().await.display_name(),
+ id: id.clone()
+ };
+ rooms_list_hack.insert(id.clone(),small_room);
+ }
+
+ let resp = Response::JoinedRoomList(rooms_list_hack);
+ agent.link.respond(*sub, resp);
+ }
+ });
+ }
}
}
@@ -202,6 +230,7 @@ impl Agent for MatrixAgent {
}
unsafe impl Send for MatrixAgent {}
+
unsafe impl std::marker::Sync for MatrixAgent {}
impl MatrixAgent {
@@ -231,9 +260,9 @@ impl MatrixAgent {
|| self.matrix_client.is_some())
&& self.session.is_none()
{
- let resp = Response::Error(MatrixError::MissingFields);
for sub in self.subscribers.iter() {
- self.link.respond(*sub, resp.clone());
+ let resp = Response::Error(MatrixError::MissingFields);
+ self.link.respond(*sub, resp);
}
None
} else if self.session.is_some() {
diff --git a/src/app/matrix/sync.rs b/src/app/matrix/sync.rs
@@ -1,12 +1,7 @@
use crate::app::matrix::Response;
use log::*;
-use matrix_sdk::{
- api::r0::sync::sync_events::Response as SyncResponse,
- events::collections::all::RoomEvent,
- events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent},
- identifiers::RoomId,
- Client, SyncSettings,
-};
+use matrix_sdk::{api::r0::sync::sync_events::Response as SyncResponse, events::collections::all::RoomEvent, events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, identifiers::RoomId, Client, SyncSettings, Error};
+use crate::app::matrix::types::MessageWrapper;
pub struct Sync<F>
where
@@ -22,7 +17,14 @@ where
{
pub async fn start_sync(&self) {
let client = self.matrix_client.clone();
- client.clone().sync(SyncSettings::default()).await.unwrap();
+ let resp = client.clone().sync(SyncSettings::default()).await;
+ match resp {
+ Ok(_) => {
+ let resp = Response::FinishedFirstSync;
+ (self.callback)(resp);
+ },
+ _ => {},
+ }
let settings = SyncSettings::default().token(client.clone().sync_token().await.unwrap());
client
@@ -54,7 +56,12 @@ where
return;
};
- let resp = Response::Sync(msg_body);
+ let wrapper = MessageWrapper {
+ room_id: room_id.clone(),
+ content: msg_body
+ };
+
+ let resp = Response::Sync(wrapper);
(self.callback)(resp);
}
}
diff --git a/src/app/matrix/types.rs b/src/app/matrix/types.rs
@@ -0,0 +1,15 @@
+use matrix_sdk::identifiers::RoomId;
+use serde::{Serialize, Deserialize};
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct SmallRoom {
+ pub(crate) name: String,
+ pub(crate) id: RoomId
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
+pub struct MessageWrapper {
+ pub(crate) room_id: RoomId,
+ // TODO use ruma structs
+ pub(crate) content: String,
+}
diff --git a/src/app/views/login.rs b/src/app/views/login.rs
@@ -70,46 +70,54 @@ impl Component for Login {
fn view(&self) -> Html {
html! {
- <div class="container h-100">
- <div class="row align-items-center h-100">
- <h1>{"Login"}</h1>
- <form class="col-6 mx-auto" onsubmit=self.link.callback(|e: Event| {e.prevent_default(); Msg::Login})>
- <div class="form-group">
- <label for="homeserver">{"Homeserver URL"}</label>
- <input
- class="form-control"
- type="url"
- id="homeserver"
- placeholder="Homeserver URL"
- value=&self.homeserver
- oninput=self.link.callback(|e: InputData| Msg::SetHomeserver(e.value))
- />
+ <div class="container">
+ <div class="uk-position-center uk-padding">
+ <h1 class="title">{"Login"}</h1>
+ <form class="uk-form-stacked uk-margin" onsubmit=self.link.callback(|e: Event| {e.prevent_default(); Msg::Login})>
+ <div class="uk-margin">
+ <label class="uk-form-label">{"Homeserver URL"}</label>
+ <div class="uk-form-controls">
+ <input
+ class="uk-input"
+ type="url"
+ id="homeserver"
+ placeholder="Homeserver URL"
+ value=&self.homeserver
+ oninput=self.link.callback(|e: InputData| Msg::SetHomeserver(e.value))
+ />
+ </div>
</div>
- <div class="form-group">
- <label for="username">{"MXID/Username"}</label>
- <input
- class="form-control"
- id="username"
- placeholder="MXID/Username"
- value=&self.username
- oninput=self.link.callback(|e: InputData| Msg::SetUsername(e.value))
- />
+ <div class="uk-margin">
+ <label class="uk-form-label">{"MXID/Username"}</label>
+ <div class="uk-form-controls">
+ <input
+ class="uk-input"
+ id="username"
+ placeholder="MXID/Username"
+ value=&self.username
+ oninput=self.link.callback(|e: InputData| Msg::SetUsername(e.value))
+ />
+ </div>
</div>
- <div class="form-group">
- <label for="password">{"Password"}</label>
- <input
- class="form-control"
- type="password"
- id="password"
- placeholder="Password"
- value=&self.password
- oninput=self.link.callback(|e: InputData| Msg::SetPassword(e.value))
- />
+ <div class="uk-margin">
+ <label class="uk-form-label">{"Password"}</label>
+ <div class="uk-form-controls">
+ <input
+ class="uk-input"
+ type="password"
+ id="password"
+ placeholder="Password"
+ value=&self.password
+ oninput=self.link.callback(|e: InputData| Msg::SetPassword(e.value))
+ />
+ </div>
</div>
- <button type="submit" class="btn btn-primary">
- { "Login" }
- </button>
+ <div class="uk-margin">
+ <div class="uk-form-controls">
+ <button class="uk-button uk-button-primary">{ "Login" }</button>
+ </div>
+ </div>
</form>
</div>
</div>
diff --git a/src/app/views/main_view.rs b/src/app/views/main_view.rs
@@ -1,10 +1,16 @@
use log::*;
-use serde_derive::{Deserialize, Serialize};
+use serde::{Deserialize, Serialize};
use yew::prelude::*;
use yew::ComponentLink;
use crate::app::matrix::{MatrixAgent, Request, Response};
-use wasm_bindgen::__rt::std::collections::{HashMap, HashSet};
+use std::collections::{HashSet, HashMap};
+use matrix_sdk::{Client, ClientConfig, Session};
+use url::Url;
+use std::convert::TryFrom;
+use wasm_bindgen_futures::spawn_local;
+use crate::app::matrix::types::{SmallRoom, MessageWrapper};
+use matrix_sdk::identifiers::RoomId;
pub struct MainView {
link: ComponentLink<Self>,
@@ -14,12 +20,15 @@ pub struct MainView {
pub enum Msg {
NewMessage(Response),
+ ChangeRoom(String)
}
#[derive(Serialize, Deserialize, Default)]
pub struct State {
// TODO handle all events
- pub events: HashSet<String>,
+ pub events: HashSet<MessageWrapper>,
+ pub rooms: HashMap<RoomId, SmallRoom>,
+ pub current_room: Option<RoomId>
}
impl Component for MainView {
@@ -32,6 +41,8 @@ impl Component for MainView {
matrix_agent.send(Request::StartSync);
let state = State {
events: Default::default(),
+ rooms: Default::default(),
+ current_room: None
};
MainView {
@@ -45,13 +56,23 @@ impl Component for MainView {
match msg {
Msg::NewMessage(response) => {
match response {
+ Response::FinishedFirstSync => {
+ self.matrix_agent.send(Request::GetJoinedRooms);
+ }
Response::Sync(msg) => {
// TODO handle all events
self.state.events.insert(msg);
}
+ Response::JoinedRoomList(rooms) => {
+ self.state.rooms = rooms
+ }
_ => {}
}
}
+ Msg::ChangeRoom(room) => {
+ self.state.current_room = Some(RoomId::try_from(room).unwrap());
+
+ }
}
true
}
@@ -61,26 +82,69 @@ impl Component for MainView {
}
fn view(&self) -> Html {
- html! {
- <div class="container-fluid h-100 non-scrollable-container">
- <div class="row h-100">
- <div class="col-md-2 scrollable h-100">
- <p>{"BLUB"}</p>
+ if !self.state.rooms.is_empty() {
+ if self.state.current_room.is_none() {
+ return html! {
+ <div class="uk-flex h-100 non-scrollable-container">
+ <div class="container h-100 uk-width-1-6">
+ <ul class="scrollable h-100 uk-padding uk-nav-default uk-nav-parent-icon" uk-nav="">
+ <li class="uk-nav-header">{"Rooms"}</li>
+ { self.state.rooms.iter().map(|(_, room)| self.get_room(room.clone())).collect::<Html>() }
+ </ul>
+ </div>
+
+ <div class="container h-100 uk-width-5-6 uk-padding">
+ <div class="scrollable h-100">
+ // TODO add some content to the empty page
+ </div>
+ </div>
</div>
- <div class="col scrollable h-100">
- { self.state.events.iter().map(|event| self.get_event(event)).collect::<Html>() }
+ }
+ } else {
+ return html! {
+ <div class="uk-flex h-100 non-scrollable-container">
+ <div class="container h-100 uk-width-1-6">
+ <ul class="scrollable h-100 uk-padding uk-nav-default uk-nav-parent-icon" uk-nav="">
+ <li class="uk-nav-header">{"Rooms"}</li>
+ { self.state.rooms.iter().map(|(_, room)| self.get_room(room.clone())).collect::<Html>() }
+ </ul>
+ </div>
+
+ <div class="container h-100 uk-width-5-6 uk-padding">
+ <h1>{ self.state.rooms.iter().filter(|(id, _)| **id == self.state.current_room.clone().unwrap()).map(|(_, room)| room.name.clone()).collect::<String>() }</h1>
+ <div class="scrollable h-100">
+ { self.state.events.iter().filter(|x| x.room_id == self.state.current_room.clone().unwrap()).map(|event| self.get_event(event.content.clone())).collect::<Html>() }
+ </div>
+ </div>
</div>
+ }
+ }
+ } else {
+ return html! {
+ <div class="container">
+ <div class="uk-position-center uk-padding">
+ <span uk-spinner="ratio: 4.5"></span>
+ </div>
</div>
- </div>
+ }
}
}
}
impl MainView {
- fn get_event(&self, event: &String) -> Html {
+ fn get_event(&self, event: String) -> Html {
+ html! {
+ <p>{event}</p>
+ }
+ }
+
+ fn get_room(&self, room: SmallRoom) -> Html {
+ // TODO better linking than onlclick (yew limitation?)
+
+ let room_id = room.clone().id.to_string();
html! {
- <><p>{event}</p><br/></>
+ <li><a href="#" onclick=self.link.callback(move |e: MouseEvent| Msg::ChangeRoom(room_id.clone()))>{room.name.clone()}</a></li>
}
}
}
diff --git a/src/errors.rs b/src/errors.rs
@@ -1,7 +1,7 @@
-use serde_derive::{Deserialize, Serialize};
+use serde::{Deserialize, Serialize};
use thiserror::Error;
-#[derive(Error, Debug, Clone, Serialize, Deserialize)]
+#[derive(Error, Debug, Copy, Clone, Serialize, Deserialize)]
pub enum MatrixError {
#[error("No Matrix Client is available yet")]
MissingClient,
diff --git a/static/index.html b/static/index.html
@@ -8,9 +8,7 @@
</head>
<body>
<script src="/daydream.js"></script>
-
- <script>
- require('bootstrap');
- </script>
- </body>
+ <script src="js/uikit.min.js"></script>
+ <script src="js/uikit-icons.min.js"></script>
+ </body>
</html>
diff --git a/static/style.scss b/static/style.scss
@@ -1,18 +1,32 @@
-html {
- height: 100%;
+.scrollable {
+ overflow-y: auto !important;
+ overflow-x: hidden !important;
+ height: 100% !important;
}
-body {
- height: 100%;
+.non-scrollable-container {
+ overflow: hidden;
}
-.scrollable {
- overflow-y: auto;
- overflow-x: hidden;
+.h-100 {
+ height: 100% !important;
}
-.non-scrollable-container {
- overflow: hidden;
+html {
+ overflow: hidden !important;
+ height: 100% !important;
+}
+
+body {
+ overflow: hidden !important;
+ height: 100% !important;
+}
+
+.menu {
+ width: 20rem;
+ padding: 1.5rem;
}
-@import "../node_modules/bootstrap/scss/bootstrap";
+@import "../node_modules/uikit/src/scss/variables-theme.scss";
+@import "../node_modules/uikit/src/scss/mixins-theme.scss";
+@import "../node_modules/uikit/src/scss/uikit-theme.scss";
diff --git a/webpack.config.js b/webpack.config.js
@@ -34,6 +34,14 @@ module.exports = (env, argv) => {
patterns: [
{
from: './static', to: distPath
+ },
+ {
+ from: './node_modules/uikit/dist/js/uikit.min.js',
+ to: path.join(distPath, '/js/uikit.min.js')
+ },
+ {
+ from: './node_modules/uikit/dist/js/uikit-icons.min.js',
+ to: path.join(distPath, '/js/uikit-icons.min.js')
}
]
}),
diff --git a/yarn.lock b/yarn.lock
@@ -508,11 +508,6 @@ bonjour@^3.5.0:
multicast-dns "^6.0.1"
multicast-dns-service-types "^1.1.0"
-bootstrap@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.0.tgz#97d9dbcb5a8972f8722c9962483543b907d9b9ec"
- integrity sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA==
-
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -4123,6 +4118,11 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+uikit@^3.4.6:
+ version "3.4.6"
+ resolved "https://registry.yarnpkg.com/uikit/-/uikit-3.4.6.tgz#39d59620aeb42d53ba905a67e99e2015d4aaaf9c"
+ integrity sha512-Se8DXGJ69NCxm8AQTok6I9aXxvklaBsdkr3REfbUorxeIQA6g96sPvzHCXrubqknoqEhH6npD14xtzxJGCvS8A==
+
union-value@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"