🎨 Reorganize the contacts_window widgets + add first interactions with homeserver
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
$font-size: 100vh * 0.01;
|
||||||
|
$icon-size: $font-size * 2;
|
||||||
|
|
||||||
body {
|
body {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
108
src/base.rs
108
src/base.rs
@@ -1,17 +1,113 @@
|
|||||||
use std::sync::Arc;
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
|
use dioxus_std::utils::rw::UseRw;
|
||||||
|
use matrix_sdk::room::Room as MatrixRoom;
|
||||||
|
use matrix_sdk::{
|
||||||
|
room::RoomMember,
|
||||||
|
ruma::{OwnedMxcUri, OwnedRoomId, OwnedUserId},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::matrix_client::Requester;
|
use crate::matrix_client::Requester;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Store {
|
pub struct UserInfo {
|
||||||
pub is_logged: bool,
|
pub avatar_url: Option<OwnedMxcUri>,
|
||||||
|
pub display_name: Option<String>,
|
||||||
|
pub blurhash: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
impl UserInfo {
|
||||||
|
pub fn new(
|
||||||
|
avatar_url: Option<OwnedMxcUri>,
|
||||||
|
display_name: Option<String>,
|
||||||
|
blurhash: Option<String>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
avatar_url,
|
||||||
|
display_name,
|
||||||
|
blurhash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Room {
|
||||||
|
pub matrix_room: Arc<MatrixRoom>,
|
||||||
|
pub topic: Option<String>,
|
||||||
|
pub members: HashMap<OwnedUserId, RoomMember>,
|
||||||
|
pub is_direct: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Room {
|
||||||
|
pub fn new(
|
||||||
|
matrix_room: Arc<MatrixRoom>,
|
||||||
|
topic: Option<String>,
|
||||||
|
is_direct: Option<bool>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
matrix_room,
|
||||||
|
topic,
|
||||||
|
members: HashMap::new(),
|
||||||
|
is_direct,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<String> {
|
||||||
|
self.matrix_room.name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Room {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
// TODO: Look for a better way to compare Matrix rooms
|
||||||
|
self.matrix_room.room_id() == other.matrix_room.room_id()
|
||||||
|
&& self.topic == other.topic
|
||||||
|
&& self.is_direct == other.is_direct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ByIdRooms = HashMap<OwnedRoomId, Arc<RwLock<Room>>>;
|
||||||
|
pub type ByIdUserInfos = HashMap<OwnedUserId, UserInfo>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Store {
|
||||||
|
pub is_logged: bool,
|
||||||
|
pub rooms: ByIdRooms,
|
||||||
|
pub user_infos: ByIdUserInfos,
|
||||||
|
pub user_id: Option<OwnedUserId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Store {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { is_logged: false }
|
Self {
|
||||||
|
is_logged: false,
|
||||||
|
rooms: HashMap::new(),
|
||||||
|
user_infos: HashMap::new(),
|
||||||
|
user_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Store {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.is_logged == other.is_logged
|
||||||
|
&& self.user_id == other.user_id
|
||||||
|
&& self.user_infos.len() == other.user_infos.len()
|
||||||
|
&& self
|
||||||
|
.user_infos
|
||||||
|
.keys()
|
||||||
|
.all(|k| other.user_infos.contains_key(k))
|
||||||
|
&& self.rooms.len() == other.rooms.len()
|
||||||
|
&& self.rooms.keys().all(|k| other.rooms.contains_key(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Store {}
|
||||||
|
|
||||||
|
pub type ReactiveStore = Arc<UseRw<Store>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppSettings {
|
pub struct AppSettings {
|
||||||
|
@@ -1,86 +0,0 @@
|
|||||||
use dioxus::prelude::*;
|
|
||||||
use dioxus_free_icons::icons::io_icons::IoChevronDown;
|
|
||||||
use dioxus_free_icons::Icon;
|
|
||||||
|
|
||||||
turf::style_sheet!("src/components/contacts.scss");
|
|
||||||
|
|
||||||
fn ContactsArrow(cx: Scope) -> Element {
|
|
||||||
cx.render(rsx! {
|
|
||||||
style { STYLE_SHEET },
|
|
||||||
|
|
||||||
Icon {
|
|
||||||
icon: IoChevronDown,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn Contacts(cx: Scope) -> Element {
|
|
||||||
let show_contacts = use_state(cx, || false);
|
|
||||||
|
|
||||||
let classes = vec![
|
|
||||||
ClassName::CONTACTS,
|
|
||||||
if **show_contacts {
|
|
||||||
ClassName::ACTIVE
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.join(" ");
|
|
||||||
|
|
||||||
cx.render(rsx! {
|
|
||||||
style { STYLE_SHEET },
|
|
||||||
|
|
||||||
div {
|
|
||||||
class: "{classes}",
|
|
||||||
|
|
||||||
p {
|
|
||||||
class: ClassName::HEADER,
|
|
||||||
onclick: move |_| show_contacts.set(!show_contacts),
|
|
||||||
|
|
||||||
ContactsArrow {},
|
|
||||||
|
|
||||||
"Online (4)",
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: Test overflow
|
|
||||||
ul {
|
|
||||||
li {
|
|
||||||
img {
|
|
||||||
src: "./images/status_online.png",
|
|
||||||
},
|
|
||||||
p {
|
|
||||||
"Contact AAAAAAAA -",
|
|
||||||
},
|
|
||||||
p {
|
|
||||||
style: "color: darkgrey;",
|
|
||||||
"i'm sad all day until i get to talk with friends, online friends that is",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
li {
|
|
||||||
img {
|
|
||||||
src: "./images/status_busy.png",
|
|
||||||
},
|
|
||||||
p {
|
|
||||||
"Contact BBBBBB -",
|
|
||||||
},
|
|
||||||
p {
|
|
||||||
style: "color: darkgrey;",
|
|
||||||
"i'm sad all day until i get to talk with friends, online friends that is",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
li {
|
|
||||||
img {
|
|
||||||
src: "./images/status_away.png",
|
|
||||||
},
|
|
||||||
p {
|
|
||||||
"Contact CCC -",
|
|
||||||
},
|
|
||||||
p {
|
|
||||||
style: "color: darkgrey;",
|
|
||||||
"i'm sad all day until i get to talk with friends, online friends that is",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
@@ -1,65 +0,0 @@
|
|||||||
.contacts {
|
|
||||||
height: 72%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: white;
|
|
||||||
font-size: 8pt;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
ul {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
height: 2%;
|
|
||||||
width: 98%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: 1%;
|
|
||||||
padding-top: 1%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
opacity: 1;
|
|
||||||
transition: 0.4s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
list-style-type: none;
|
|
||||||
height: 2%;
|
|
||||||
margin: 0 auto;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 100%;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
transition: 0.4s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
text-align: left;
|
|
||||||
cursor: pointer
|
|
||||||
}
|
|
||||||
}
|
|
47
src/components/contacts_window/contacts.rs
Normal file
47
src/components/contacts_window/contacts.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_std::utils::rw::UseRw;
|
||||||
|
|
||||||
|
use crate::base::Room;
|
||||||
|
use crate::base::Store;
|
||||||
|
use crate::components::contacts_window::contacts_section::ContactsSection;
|
||||||
|
|
||||||
|
turf::style_sheet!("src/components/contacts_window/contacts.scss");
|
||||||
|
|
||||||
|
#[inline_props]
|
||||||
|
pub fn Contacts<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||||
|
println!("Contacts rendering");
|
||||||
|
|
||||||
|
let store = rw_store.read().unwrap();
|
||||||
|
|
||||||
|
let rooms = &store.rooms;
|
||||||
|
|
||||||
|
let rooms_len = rooms.len();
|
||||||
|
let mut groups = Vec::<Room>::with_capacity(rooms_len);
|
||||||
|
let mut directs = Vec::<Room>::with_capacity(rooms_len);
|
||||||
|
|
||||||
|
for arc_room in rooms.values() {
|
||||||
|
let room = arc_room.read().unwrap().to_owned();
|
||||||
|
|
||||||
|
let is_direct = room.is_direct.unwrap();
|
||||||
|
if is_direct {
|
||||||
|
directs.push(room);
|
||||||
|
} else {
|
||||||
|
groups.push(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test overflow
|
||||||
|
// TODO: Add offline users ?
|
||||||
|
cx.render(rsx! {
|
||||||
|
style { STYLE_SHEET },
|
||||||
|
|
||||||
|
div {
|
||||||
|
class: ClassName::CONTACTS,
|
||||||
|
|
||||||
|
ContactsSection {name: "Groups", contacts: RefCell::new(groups)},
|
||||||
|
ContactsSection {name: "Available", contacts: RefCell::new(directs)},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
6
src/components/contacts_window/contacts.scss
Normal file
6
src/components/contacts_window/contacts.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@import "../../_base.scss"
|
||||||
|
|
||||||
|
.contacts {
|
||||||
|
height: 72%;
|
||||||
|
background-color: white;
|
||||||
|
}
|
87
src/components/contacts_window/contacts_section.rs
Normal file
87
src/components/contacts_window/contacts_section.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_free_icons::icons::io_icons::IoChevronDown;
|
||||||
|
use dioxus_free_icons::Icon;
|
||||||
|
use matrix_sdk::RoomState;
|
||||||
|
|
||||||
|
use crate::base::Room;
|
||||||
|
|
||||||
|
turf::style_sheet!("src/components/contacts_window/contacts_section.scss");
|
||||||
|
|
||||||
|
fn ContactsArrow(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx! {
|
||||||
|
style { STYLE_SHEET },
|
||||||
|
|
||||||
|
Icon {
|
||||||
|
icon: IoChevronDown,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static NO_SUBJECT_REPR: &str = "No subject";
|
||||||
|
|
||||||
|
#[inline_props]
|
||||||
|
pub fn ContactsSection<'a>(cx: Scope, name: &'a str, contacts: RefCell<Vec<Room>>) -> Element {
|
||||||
|
println!("ContactsSection rendering");
|
||||||
|
|
||||||
|
let show = use_state(cx, || false);
|
||||||
|
|
||||||
|
let classes = vec![
|
||||||
|
ClassName::SECTION,
|
||||||
|
if **show { ClassName::ACTIVE } else { "" },
|
||||||
|
]
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
|
let contacts_len = contacts.borrow().len();
|
||||||
|
|
||||||
|
let rendered_contacts = contacts.borrow_mut().clone().into_iter().map(|room| {
|
||||||
|
let room_name = room.name().unwrap();
|
||||||
|
let is_invited = room.matrix_room.state() == RoomState::Invited;
|
||||||
|
let formatted = format!(
|
||||||
|
"{room_name} - {}",
|
||||||
|
if is_invited {
|
||||||
|
format!("Invited - ")
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let room_topic = room.topic.unwrap_or(NO_SUBJECT_REPR.to_string()).to_owned();
|
||||||
|
|
||||||
|
rsx!(li {
|
||||||
|
img {
|
||||||
|
src: "./images/status_online.png",
|
||||||
|
},
|
||||||
|
p {
|
||||||
|
formatted,
|
||||||
|
},
|
||||||
|
p {
|
||||||
|
style: "color: darkgrey;",
|
||||||
|
room_topic,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.render(rsx! {
|
||||||
|
style { STYLE_SHEET },
|
||||||
|
|
||||||
|
div {
|
||||||
|
class: "{classes}",
|
||||||
|
|
||||||
|
p {
|
||||||
|
class: ClassName::HEADER,
|
||||||
|
onclick: move |_| show.set(!show),
|
||||||
|
|
||||||
|
ContactsArrow {},
|
||||||
|
|
||||||
|
format!("{name} ({contacts_len})"),
|
||||||
|
},
|
||||||
|
|
||||||
|
ul {
|
||||||
|
rendered_contacts.into_iter(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
67
src/components/contacts_window/contacts_section.scss
Normal file
67
src/components/contacts_window/contacts_section.scss
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
@import "../../_base.scss"
|
||||||
|
|
||||||
|
.section {
|
||||||
|
width: 100%;
|
||||||
|
font-size: $font-size;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
ul {
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 2%;
|
||||||
|
width: 98%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0;
|
||||||
|
margin-left: 1%;
|
||||||
|
padding-top: 1%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 1;
|
||||||
|
transition: 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: $icon-size;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
transition: 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer
|
||||||
|
}
|
||||||
|
}
|
@@ -1,16 +1,14 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_std::utils::rw::UseRw;
|
||||||
|
|
||||||
use crate::app_settings::AppSettings;
|
use crate::base::Store;
|
||||||
use crate::components::contacts::Contacts;
|
use crate::components::contacts_window::contacts::Contacts;
|
||||||
use crate::components::header::Header;
|
use crate::components::contacts_window::user_infos::UserInfos;
|
||||||
use crate::components::user_infos::UserInfos;
|
|
||||||
|
|
||||||
turf::style_sheet!("src/components/contacts_window.scss");
|
|
||||||
|
|
||||||
pub fn ContactWindow(cx: Scope) -> Element {
|
|
||||||
let app_context = use_shared_state::<AppSettings>(cx).unwrap();
|
|
||||||
|
|
||||||
|
turf::style_sheet!("src/components/contacts_window/contacts_window.scss");
|
||||||
|
|
||||||
|
#[inline_props]
|
||||||
|
pub fn ContactsWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
style { STYLE_SHEET },
|
style { STYLE_SHEET },
|
||||||
|
|
||||||
@@ -28,7 +26,7 @@ pub fn ContactWindow(cx: Scope) -> Element {
|
|||||||
class: ClassName::USER_INFO,
|
class: ClassName::USER_INFO,
|
||||||
},
|
},
|
||||||
|
|
||||||
UserInfos {},
|
UserInfos {rw_store: rw_store},
|
||||||
},
|
},
|
||||||
|
|
||||||
div {
|
div {
|
||||||
@@ -86,7 +84,7 @@ pub fn ContactWindow(cx: Scope) -> Element {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
Contacts {},
|
Contacts {rw_store: rw_store},
|
||||||
|
|
||||||
div {
|
div {
|
||||||
class: ClassName::FOOTER,
|
class: ClassName::FOOTER,
|
@@ -1,4 +1,4 @@
|
|||||||
@import "../_base.scss";
|
@import "../../_base.scss";
|
||||||
|
|
||||||
.contactsWindow {
|
.contactsWindow {
|
||||||
width: 100%;
|
width: 100%;
|
5
src/components/contacts_window/mod.rs
Normal file
5
src/components/contacts_window/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub mod contacts_window;
|
||||||
|
|
||||||
|
mod contacts;
|
||||||
|
mod contacts_section;
|
||||||
|
mod user_infos;
|
@@ -1,10 +1,12 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_free_icons::icons::md_navigation_icons::MdArrowDropDown;
|
use dioxus_free_icons::icons::md_navigation_icons::MdArrowDropDown;
|
||||||
use dioxus_free_icons::Icon;
|
use dioxus_free_icons::Icon;
|
||||||
|
use dioxus_std::utils::rw::UseRw;
|
||||||
|
|
||||||
|
use crate::base::Store;
|
||||||
use crate::components::avatar_selector::AvatarSelector;
|
use crate::components::avatar_selector::AvatarSelector;
|
||||||
|
|
||||||
turf::style_sheet!("src/components/user_infos.scss");
|
turf::style_sheet!("src/components/contacts_window/user_infos.scss");
|
||||||
|
|
||||||
fn DownArrowIcon(cx: Scope) -> Element {
|
fn DownArrowIcon(cx: Scope) -> Element {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
@@ -17,7 +19,18 @@ fn DownArrowIcon(cx: Scope) -> Element {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn UserInfos(cx: Scope) -> Element {
|
static MESSAGE_PLACEHOLDER: &str = "<Enter a personal message>";
|
||||||
|
|
||||||
|
#[inline_props]
|
||||||
|
pub fn UserInfos<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||||
|
println!("UserInfos rendering");
|
||||||
|
|
||||||
|
let store = rw_store.read().unwrap().clone();
|
||||||
|
|
||||||
|
let user_id = store.user_id.unwrap();
|
||||||
|
let user_info = store.user_infos.get(&user_id).unwrap();
|
||||||
|
let user_display_name = user_info.display_name.as_ref().unwrap();
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
style { STYLE_SHEET },
|
style { STYLE_SHEET },
|
||||||
|
|
||||||
@@ -36,7 +49,7 @@ pub fn UserInfos(cx: Scope) -> Element {
|
|||||||
class: ClassName::USER_ID,
|
class: ClassName::USER_ID,
|
||||||
p {
|
p {
|
||||||
class: ClassName::USER_NAME,
|
class: ClassName::USER_NAME,
|
||||||
"SUPER USER"
|
"{user_display_name}",
|
||||||
},
|
},
|
||||||
p {
|
p {
|
||||||
class: ClassName::USER_STATUS,
|
class: ClassName::USER_STATUS,
|
||||||
@@ -48,7 +61,8 @@ pub fn UserInfos(cx: Scope) -> Element {
|
|||||||
div {
|
div {
|
||||||
class: ClassName::USER_MESSAGE,
|
class: ClassName::USER_MESSAGE,
|
||||||
p {
|
p {
|
||||||
"My message",
|
// TODO: Handle user message
|
||||||
|
MESSAGE_PLACEHOLDER,
|
||||||
}
|
}
|
||||||
DownArrowIcon {},
|
DownArrowIcon {},
|
||||||
},
|
},
|
@@ -1,4 +1,4 @@
|
|||||||
@import "../_base.scss"
|
@import "../../_base.scss"
|
||||||
|
|
||||||
.userInfo {
|
.userInfo {
|
||||||
position: relative;
|
position: relative;
|
@@ -11,19 +11,15 @@ use crate::matrix_client::{LoginStyle, MatrixClient};
|
|||||||
|
|
||||||
turf::style_sheet!("src/components/login.scss");
|
turf::style_sheet!("src/components/login.scss");
|
||||||
|
|
||||||
#[derive(Props)]
|
static EMPTY_PLACEHOLDER: &str = "Tmp placeholder";
|
||||||
pub struct LoginProps<'a> {
|
|
||||||
pub store: &'a mut UseRw<Store>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
|
#[inline_props]
|
||||||
|
pub fn Login<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||||
let app_context = use_shared_state::<AppSettings>(cx).unwrap();
|
let app_context = use_shared_state::<AppSettings>(cx).unwrap();
|
||||||
let invalid_login = use_state(cx, || false);
|
let invalid_login = use_state(cx, || false);
|
||||||
let login = use_ref(cx, || Login::new());
|
let login = use_ref(cx, || Login::new());
|
||||||
|
|
||||||
let store = cx.props.store.clone();
|
let arc_store = Arc::new(rw_store.to_owned().clone());
|
||||||
|
|
||||||
let empty_placeholder = String::from("");
|
|
||||||
|
|
||||||
let password_class = if **invalid_login {
|
let password_class = if **invalid_login {
|
||||||
ClassName::INVALID_INPUT
|
ClassName::INVALID_INPUT
|
||||||
@@ -33,14 +29,15 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
|
|||||||
|
|
||||||
let run_matrix_client = move |_| {
|
let run_matrix_client = move |_| {
|
||||||
cx.spawn({
|
cx.spawn({
|
||||||
to_owned![app_context, invalid_login, login, store];
|
to_owned![app_context, invalid_login, login, arc_store];
|
||||||
|
|
||||||
let homeserver_url = login.read().homeserver_url.clone().unwrap();
|
let login_ref = login.read();
|
||||||
let username = login.read().email.clone().unwrap();
|
let homeserver_url = login_ref.homeserver_url.clone().unwrap();
|
||||||
let password = login.read().password.clone().unwrap();
|
let username = login_ref.email.clone().unwrap();
|
||||||
|
let password = login_ref.password.clone().unwrap();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let requester = MatrixClient::spawn(homeserver_url, store).await;
|
let requester = MatrixClient::spawn(homeserver_url, arc_store.clone()).await;
|
||||||
requester.init();
|
requester.init();
|
||||||
|
|
||||||
match requester.login(LoginStyle::Password(username, password)) {
|
match requester.login(LoginStyle::Password(username, password)) {
|
||||||
@@ -58,6 +55,12 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let login_ref = login.read();
|
||||||
|
let placeholder = EMPTY_PLACEHOLDER.to_string();
|
||||||
|
let homeserver_url_value = login_ref.homeserver_url.as_ref().unwrap_or(&placeholder);
|
||||||
|
let email_value = login_ref.email.as_ref().unwrap_or(&placeholder);
|
||||||
|
let password_value = login_ref.password.as_ref().unwrap_or(&placeholder);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
style { STYLE_SHEET },
|
style { STYLE_SHEET },
|
||||||
|
|
||||||
@@ -83,7 +86,7 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
|
|||||||
id: "input-homeserver-url",
|
id: "input-homeserver-url",
|
||||||
r#type: "text",
|
r#type: "text",
|
||||||
name: "homeserver URL",
|
name: "homeserver URL",
|
||||||
value: "{(login.read().homeserver_url.as_ref().unwrap_or(&empty_placeholder))}",
|
value: "{homeserver_url_value}",
|
||||||
oninput: move |evt| login.write().homeserver_url = Some(evt.value.clone()),
|
oninput: move |evt| login.write().homeserver_url = Some(evt.value.clone()),
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -94,7 +97,7 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
|
|||||||
id: "login-input-email",
|
id: "login-input-email",
|
||||||
r#type: "text",
|
r#type: "text",
|
||||||
name: "email",
|
name: "email",
|
||||||
value: "{login.read().email.as_ref().unwrap_or(&empty_placeholder)}",
|
value: "{email_value}",
|
||||||
oninput: move |evt| login.write().email = Some(evt.value.clone()),
|
oninput: move |evt| login.write().email = Some(evt.value.clone()),
|
||||||
},
|
},
|
||||||
p {
|
p {
|
||||||
@@ -105,7 +108,7 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
|
|||||||
id: "login-input-password",
|
id: "login-input-password",
|
||||||
r#type: "password",
|
r#type: "password",
|
||||||
name: "Password",
|
name: "Password",
|
||||||
value: "{login.read().password.as_ref().unwrap_or(&empty_placeholder)}",
|
value: "{password_value}",
|
||||||
oninput: move |evt| {
|
oninput: move |evt| {
|
||||||
login.write().password = Some(evt.value.clone());
|
login.write().password = Some(evt.value.clone());
|
||||||
invalid_login.set(false);
|
invalid_login.set(false);
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
pub mod avatar_selector;
|
pub mod avatar_selector;
|
||||||
pub mod contacts;
|
|
||||||
pub mod contacts_window;
|
pub mod contacts_window;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod user_infos;
|
|
11
src/main.rs
11
src/main.rs
@@ -1,4 +1,5 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_desktop::Config;
|
use dioxus_desktop::Config;
|
||||||
use dioxus_std::utils::rw::use_rw;
|
use dioxus_std::utils::rw::use_rw;
|
||||||
@@ -7,7 +8,7 @@ pub mod components;
|
|||||||
pub mod matrix_client;
|
pub mod matrix_client;
|
||||||
|
|
||||||
use crate::base::{AppSettings, Store};
|
use crate::base::{AppSettings, Store};
|
||||||
use crate::components::contacts_window::ContactWindow;
|
use crate::components::contacts_window::contacts_window::ContactsWindow;
|
||||||
use crate::components::login::Login;
|
use crate::components::login::Login;
|
||||||
|
|
||||||
mod base;
|
mod base;
|
||||||
@@ -15,16 +16,16 @@ mod base;
|
|||||||
fn App(cx: Scope<AppSettings>) -> Element {
|
fn App(cx: Scope<AppSettings>) -> Element {
|
||||||
use_shared_state_provider(cx, || cx.props.clone());
|
use_shared_state_provider(cx, || cx.props.clone());
|
||||||
|
|
||||||
let store = use_rw(cx, || Store::new());
|
let rw_store = use_rw(cx, || Store::new());
|
||||||
|
|
||||||
let is_logged = store.read().unwrap().is_logged;
|
let is_logged = rw_store.read().unwrap().is_logged;
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
if is_logged {
|
if is_logged {
|
||||||
rsx!(ContactWindow {})
|
rsx!(ContactsWindow {rw_store: rw_store})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rsx!(Login {store: store})
|
rsx!(Login {rw_store: rw_store})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,42 @@
|
|||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, RwLock};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use dioxus_std::utils::rw::UseRw;
|
use dioxus_std::utils::rw::UseRw;
|
||||||
use matrix_sdk::{
|
|
||||||
config::SyncSettings,
|
|
||||||
room::Room as MatrixRoom,
|
|
||||||
ruma::events::{presence::PresenceEvent, typing::SyncTypingEvent},
|
|
||||||
Client,
|
|
||||||
};
|
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
use crate::base::Store;
|
use matrix_sdk::{
|
||||||
|
config::SyncSettings,
|
||||||
|
event_handler::Ctx,
|
||||||
|
room::Room as MatrixRoom,
|
||||||
|
ruma::{
|
||||||
|
events::{
|
||||||
|
key::verification::{
|
||||||
|
done::{OriginalSyncKeyVerificationDoneEvent, ToDeviceKeyVerificationDoneEvent},
|
||||||
|
key::{OriginalSyncKeyVerificationKeyEvent, ToDeviceKeyVerificationKeyEvent},
|
||||||
|
request::ToDeviceKeyVerificationRequestEvent,
|
||||||
|
start::{OriginalSyncKeyVerificationStartEvent, ToDeviceKeyVerificationStartEvent},
|
||||||
|
},
|
||||||
|
presence::PresenceEvent,
|
||||||
|
reaction::ReactionEventContent,
|
||||||
|
room::{
|
||||||
|
member::{OriginalSyncRoomMemberEvent, RoomMemberEventContent},
|
||||||
|
message::RoomMessageEventContent,
|
||||||
|
name::RoomNameEventContent,
|
||||||
|
redaction::OriginalSyncRoomRedactionEvent,
|
||||||
|
topic::RoomTopicEventContent,
|
||||||
|
},
|
||||||
|
typing::SyncTypingEvent,
|
||||||
|
SyncMessageLikeEvent, SyncStateEvent,
|
||||||
|
},
|
||||||
|
OwnedRoomId, OwnedUserId,
|
||||||
|
},
|
||||||
|
Client, DisplayName, RoomMemberships,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::base::{ByIdRooms, ReactiveStore, Room, Store, UserInfo};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoginStyle {
|
pub enum LoginStyle {
|
||||||
@@ -78,7 +102,7 @@ fn oneshot<T>() -> (ClientReply<T>, ClientResponse<T>) {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Requester {
|
pub struct Requester {
|
||||||
pub client: Client,
|
pub client: Arc<Client>,
|
||||||
pub tx: UnboundedSender<WorkerTask>,
|
pub tx: UnboundedSender<WorkerTask>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,35 +130,42 @@ impl Requester {
|
|||||||
|
|
||||||
pub struct MatrixClient {
|
pub struct MatrixClient {
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
client: Option<Arc<Client>>,
|
client: Arc<Client>,
|
||||||
// sync_token: Option<String>,
|
// sync_token: Option<String>,
|
||||||
// load_handle: Option<JoinHandle<()>>,
|
load_handle: Option<JoinHandle<()>>,
|
||||||
sync_handle: Option<JoinHandle<()>>,
|
sync_handle: Option<JoinHandle<()>>,
|
||||||
store: UseRw<Store>,
|
store: ReactiveStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatrixClient {
|
impl MatrixClient {
|
||||||
pub async fn spawn(homeserver_url: String, store: UseRw<Store>) -> Requester {
|
fn new(store: ReactiveStore, client: Arc<Client>) -> Self {
|
||||||
|
Self {
|
||||||
|
client: client,
|
||||||
|
initialized: false,
|
||||||
|
// sync_token: None,
|
||||||
|
load_handle: None,
|
||||||
|
sync_handle: None,
|
||||||
|
store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn spawn(homeserver_url: String, store: ReactiveStore) -> Requester {
|
||||||
let (tx, rx) = unbounded_channel::<WorkerTask>();
|
let (tx, rx) = unbounded_channel::<WorkerTask>();
|
||||||
|
|
||||||
let client = Client::builder()
|
let client = Arc::new(
|
||||||
|
Client::builder()
|
||||||
.homeserver_url(&homeserver_url)
|
.homeserver_url(&homeserver_url)
|
||||||
.build()
|
.build()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
let mut matrix_client = MatrixClient {
|
let mut matrix_client = MatrixClient::new(store, client.clone());
|
||||||
client: None,
|
|
||||||
initialized: false,
|
|
||||||
// sync_token: None,
|
|
||||||
// load_handle: None,
|
|
||||||
sync_handle: None,
|
|
||||||
store: store,
|
|
||||||
};
|
|
||||||
matrix_client.client = Some(Arc::new(client.clone()));
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn({
|
||||||
|
async move {
|
||||||
matrix_client.work(rx).await;
|
matrix_client.work(rx).await;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Requester { client, tx }
|
Requester { client, tx }
|
||||||
@@ -176,27 +207,289 @@ impl MatrixClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_sync_event(_ev: SyncTypingEvent, room: MatrixRoom) {
|
async fn on_sync_typing_event(
|
||||||
println!("== on_sync_event ==");
|
_ev: SyncTypingEvent,
|
||||||
|
room: MatrixRoom,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_sync_typing_event ==");
|
||||||
let room_id = room.room_id().to_owned();
|
let room_id = room.room_id().to_owned();
|
||||||
dbg!(room_id);
|
// dbg!(room_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_presence_event(_ev: PresenceEvent) {
|
async fn on_presence_event(_ev: PresenceEvent, _store: Ctx<ReactiveStore>) {
|
||||||
println!("== on_presence_event ==");
|
println!("== on_presence_event ==");
|
||||||
|
dbg!(_ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_sync_state_event(
|
||||||
|
_ev: SyncStateEvent<RoomNameEventContent>,
|
||||||
|
_room: MatrixRoom,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_sync_state_event ==");
|
||||||
|
dbg!(_ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_room_topic_event(
|
||||||
|
ev: SyncStateEvent<RoomTopicEventContent>,
|
||||||
|
room: MatrixRoom,
|
||||||
|
reactive_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
dbg!(&ev);
|
||||||
|
if let SyncStateEvent::Original(ev) = ev {
|
||||||
|
let room_id = room.room_id().to_owned();
|
||||||
|
let store = reactive_store.read().unwrap().to_owned();
|
||||||
|
|
||||||
|
if let Some(store_room) = store.rooms.get(&room_id) {
|
||||||
|
store_room.write().unwrap().topic = Some(ev.content.topic);
|
||||||
|
let _ = reactive_store.write(store);
|
||||||
|
println!("HOP");
|
||||||
|
} else {
|
||||||
|
println!("No room with \"{room_id}\" id known");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_room_member_event(
|
||||||
|
ev: SyncStateEvent<RoomMemberEventContent>,
|
||||||
|
room: MatrixRoom,
|
||||||
|
store_ctx: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_room_member_event ==");
|
||||||
|
// // dbg!(ev);
|
||||||
|
// // dbg!(room);
|
||||||
|
// if room.invited_members_count() > 0 {
|
||||||
|
// dbg!(room);
|
||||||
|
// }
|
||||||
|
// if let SyncStateEvent::Original(ev) = ev {}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_sync_message_like_room_message_event(
|
||||||
|
_ev: SyncMessageLikeEvent<RoomMessageEventContent>,
|
||||||
|
_room: MatrixRoom,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_sync_message_like_room_message_event ==");
|
||||||
|
// dbg!(_ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_sync_message_like_reaction_event(
|
||||||
|
_ev: SyncMessageLikeEvent<ReactionEventContent>,
|
||||||
|
_room: MatrixRoom,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_sync_message_like_reaction_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_original_sync_room_redaction_event(
|
||||||
|
_ev: OriginalSyncRoomRedactionEvent,
|
||||||
|
_room: MatrixRoom,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_original_sync_room_redaction_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_original_sync_room_member_event(
|
||||||
|
_ev: OriginalSyncRoomMemberEvent,
|
||||||
|
room: MatrixRoom,
|
||||||
|
_client: Client,
|
||||||
|
store_ctx: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_original_sync_room_member_event ==");
|
||||||
|
let room_id = room.room_id();
|
||||||
|
dbg!(room_id);
|
||||||
|
|
||||||
|
let mut store = store_ctx.read().unwrap().to_owned();
|
||||||
|
dbg!(store.rooms.keys());
|
||||||
|
let is_direct = room.is_direct().await.ok();
|
||||||
|
store.rooms.insert(
|
||||||
|
OwnedRoomId::from(room_id),
|
||||||
|
Arc::new(RwLock::new(Room::new(Arc::new(room), None, is_direct))),
|
||||||
|
);
|
||||||
|
let _ = store_ctx.write(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_original_sync_key_verif_start_event(
|
||||||
|
_ev: OriginalSyncKeyVerificationStartEvent,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_original_sync_key_verif_start_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_original_sync_key_verif_key_event(
|
||||||
|
_ev: OriginalSyncKeyVerificationKeyEvent,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_original_sync_key_verif_key_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_original_sync_key_verif_done_event(
|
||||||
|
_ev: OriginalSyncKeyVerificationDoneEvent,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_original_sync_key_verif_done_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_device_key_verif_req_event(
|
||||||
|
_ev: ToDeviceKeyVerificationRequestEvent,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_device_key_verif_req_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_device_key_verif_start_event(
|
||||||
|
_ev: ToDeviceKeyVerificationStartEvent,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_device_key_verif_start_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_device_key_verif_key_event(
|
||||||
|
_ev: ToDeviceKeyVerificationKeyEvent,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_device_key_verif_key_event ==");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_device_key_verif_done_event(
|
||||||
|
_ev: ToDeviceKeyVerificationDoneEvent,
|
||||||
|
_client: Client,
|
||||||
|
_store: Ctx<ReactiveStore>,
|
||||||
|
) {
|
||||||
|
println!("== on_device_key_verif_done_event ==");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init(&mut self) {
|
async fn init(&mut self) {
|
||||||
self.initialized = true;
|
let client = self.client.clone();
|
||||||
|
let store = self.store.clone();
|
||||||
|
client.add_event_handler_context(store);
|
||||||
|
|
||||||
let client = self.client.clone().unwrap();
|
let _ = client.add_event_handler(MatrixClient::on_sync_typing_event);
|
||||||
|
|
||||||
let _ = client.add_event_handler(MatrixClient::on_sync_event);
|
|
||||||
let _ = client.add_event_handler(MatrixClient::on_presence_event);
|
let _ = client.add_event_handler(MatrixClient::on_presence_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_sync_state_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_sync_message_like_room_message_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_sync_message_like_reaction_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_original_sync_room_redaction_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_original_sync_room_member_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_original_sync_key_verif_start_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_original_sync_key_verif_key_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_original_sync_key_verif_done_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_device_key_verif_req_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_device_key_verif_start_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_device_key_verif_key_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_device_key_verif_done_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_room_topic_event);
|
||||||
|
let _ = client.add_event_handler(MatrixClient::on_room_member_event);
|
||||||
|
|
||||||
|
self.load_handle = tokio::spawn({
|
||||||
|
let client = self.client.clone();
|
||||||
|
let store = self.store.clone();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
let rooms_refresh = Self::refresh_rooms_forever(client.as_ref(), store.as_ref());
|
||||||
|
let ((),) = tokio::join!(rooms_refresh);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
|
self.initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn load_user_infos(&self) {
|
||||||
|
let mut store = self.store.read().unwrap().to_owned();
|
||||||
|
|
||||||
|
let user_id = self.client.user_id().unwrap();
|
||||||
|
store.user_id = Some(OwnedUserId::from(user_id));
|
||||||
|
|
||||||
|
let res = self.client.account().get_profile().await.unwrap();
|
||||||
|
let user_info = UserInfo::new(res.avatar_url, res.displayname, res.blurhash);
|
||||||
|
|
||||||
|
store
|
||||||
|
.user_infos
|
||||||
|
.insert(OwnedUserId::from(user_id), user_info);
|
||||||
|
|
||||||
|
let _ = self.store.write(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_formatted_room_name(room: &MatrixRoom) -> String {
|
||||||
|
room.display_name()
|
||||||
|
.await
|
||||||
|
.unwrap_or(DisplayName::Empty)
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refresh_rooms(client: &Client, store: &UseRw<Store>) {
|
||||||
|
// println!("== refresh_rooms ==");
|
||||||
|
|
||||||
|
let mut _store = store.read().unwrap().to_owned();
|
||||||
|
|
||||||
|
let mut new_rooms = ByIdRooms::new();
|
||||||
|
|
||||||
|
for room in &client.joined_rooms() {
|
||||||
|
let room_id = room.room_id();
|
||||||
|
|
||||||
|
let members = room.members(RoomMemberships::empty()).await.unwrap();
|
||||||
|
if !_store.rooms.contains_key(room_id) {
|
||||||
|
let is_direct = room.is_direct().await.ok();
|
||||||
|
new_rooms.insert(
|
||||||
|
OwnedRoomId::from(room_id),
|
||||||
|
Arc::new(RwLock::new(Room::new(
|
||||||
|
Arc::new(room.to_owned()),
|
||||||
|
None,
|
||||||
|
is_direct,
|
||||||
|
))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for room in client.invited_rooms().into_iter() {
|
||||||
|
let room_id = room.room_id();
|
||||||
|
|
||||||
|
if !_store.rooms.contains_key(room_id) {
|
||||||
|
let is_direct = room.is_direct().await.ok();
|
||||||
|
new_rooms.insert(
|
||||||
|
OwnedRoomId::from(room_id),
|
||||||
|
Arc::new(RwLock::new(Room::new(
|
||||||
|
Arc::new(room.to_owned()),
|
||||||
|
None,
|
||||||
|
is_direct,
|
||||||
|
))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut updated = false;
|
||||||
|
for (room_id, room) in new_rooms.into_iter() {
|
||||||
|
updated = true;
|
||||||
|
_store.rooms.insert(room_id, room);
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
let _ = store.write(_store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refresh_rooms_forever(client: &Client, store: &UseRw<Store>) {
|
||||||
|
// TODO: Add interval to config
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
Self::refresh_rooms(client, store).await;
|
||||||
|
|
||||||
|
interval.tick().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn login_and_sync(&mut self, style: LoginStyle) -> anyhow::Result<()> {
|
async fn login_and_sync(&mut self, style: LoginStyle) -> anyhow::Result<()> {
|
||||||
let client = self.client.clone().unwrap();
|
let client = self.client.clone();
|
||||||
|
|
||||||
match style {
|
match style {
|
||||||
LoginStyle::Password(username, password) => {
|
LoginStyle::Password(username, password) => {
|
||||||
@@ -210,22 +503,24 @@ impl MatrixClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sync_handle = tokio::spawn(async move {
|
self.load_user_infos().await;
|
||||||
// Sync once so we receive the client state and old messages
|
|
||||||
let _ret = client.sync_once(SyncSettings::default()).await;
|
|
||||||
|
|
||||||
let _rooms = client.rooms();
|
self.sync_handle = tokio::spawn({
|
||||||
|
async move {
|
||||||
|
// Sync once so we receive the client state and old messages
|
||||||
|
let _ = client.sync_once(SyncSettings::default()).await;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let settings = SyncSettings::default();
|
let settings = SyncSettings::default();
|
||||||
let _ = client.sync(settings).await;
|
let _ = client.sync(settings).await;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let mut store = self.store.read().unwrap().to_owned();
|
let mut store = self.store.read().unwrap().to_owned();
|
||||||
store.is_logged = true;
|
store.is_logged = true;
|
||||||
let _ = self.store.write(store).unwrap();
|
let _ = self.store.write(store);
|
||||||
|
|
||||||
println!("User connected to the homeserver");
|
println!("User connected to the homeserver");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Reference in New Issue
Block a user