🎨 Reorganize the contacts_window widgets + add first interactions with homeserver

This commit is contained in:
2023-08-15 22:05:26 +02:00
parent 22ef914304
commit 2159c6adeb
17 changed files with 712 additions and 243 deletions

View File

@@ -1,3 +1,6 @@
$font-size: 100vh * 0.01;
$icon-size: $font-size * 2;
body {
height: 100vh;
width: 100vw;

View File

@@ -1,18 +1,114 @@
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;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Store {
pub is_logged: bool,
#[derive(Clone, Debug)]
pub struct UserInfo {
pub avatar_url: Option<OwnedMxcUri>,
pub display_name: Option<String>,
pub blurhash: Option<String>,
}
impl Store {
pub fn new() -> Self {
Self { is_logged: false }
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 {
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)]
pub struct AppSettings {
pub requester: Option<Arc<Requester>>,

View File

@@ -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",
}
},
},
},
})
}

View File

@@ -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
}
}

View 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)},
},
})
}

View File

@@ -0,0 +1,6 @@
@import "../../_base.scss"
.contacts {
height: 72%;
background-color: white;
}

View 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(),
},
},
})
}

View 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
}
}

View File

@@ -1,16 +1,14 @@
use dioxus::prelude::*;
use dioxus_std::utils::rw::UseRw;
use crate::app_settings::AppSettings;
use crate::components::contacts::Contacts;
use crate::components::header::Header;
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();
use crate::base::Store;
use crate::components::contacts_window::contacts::Contacts;
use crate::components::contacts_window::user_infos::UserInfos;
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! {
style { STYLE_SHEET },
@@ -28,7 +26,7 @@ pub fn ContactWindow(cx: Scope) -> Element {
class: ClassName::USER_INFO,
},
UserInfos {},
UserInfos {rw_store: rw_store},
},
div {
@@ -86,7 +84,7 @@ pub fn ContactWindow(cx: Scope) -> Element {
},
},
Contacts {},
Contacts {rw_store: rw_store},
div {
class: ClassName::FOOTER,

View File

@@ -1,4 +1,4 @@
@import "../_base.scss";
@import "../../_base.scss";
.contactsWindow {
width: 100%;

View File

@@ -0,0 +1,5 @@
pub mod contacts_window;
mod contacts;
mod contacts_section;
mod user_infos;

View File

@@ -1,10 +1,12 @@
use dioxus::prelude::*;
use dioxus_free_icons::icons::md_navigation_icons::MdArrowDropDown;
use dioxus_free_icons::Icon;
use dioxus_std::utils::rw::UseRw;
use crate::base::Store;
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 {
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! {
style { STYLE_SHEET },
@@ -36,7 +49,7 @@ pub fn UserInfos(cx: Scope) -> Element {
class: ClassName::USER_ID,
p {
class: ClassName::USER_NAME,
"SUPER USER"
"{user_display_name}",
},
p {
class: ClassName::USER_STATUS,
@@ -48,7 +61,8 @@ pub fn UserInfos(cx: Scope) -> Element {
div {
class: ClassName::USER_MESSAGE,
p {
"My message",
// TODO: Handle user message
MESSAGE_PLACEHOLDER,
}
DownArrowIcon {},
},

View File

@@ -1,4 +1,4 @@
@import "../_base.scss"
@import "../../_base.scss"
.userInfo {
position: relative;

View File

@@ -11,19 +11,15 @@ use crate::matrix_client::{LoginStyle, MatrixClient};
turf::style_sheet!("src/components/login.scss");
#[derive(Props)]
pub struct LoginProps<'a> {
pub store: &'a mut UseRw<Store>,
}
static EMPTY_PLACEHOLDER: &str = "Tmp placeholder";
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 invalid_login = use_state(cx, || false);
let login = use_ref(cx, || Login::new());
let store = cx.props.store.clone();
let empty_placeholder = String::from("");
let arc_store = Arc::new(rw_store.to_owned().clone());
let password_class = if **invalid_login {
ClassName::INVALID_INPUT
@@ -33,14 +29,15 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
let run_matrix_client = move |_| {
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 username = login.read().email.clone().unwrap();
let password = login.read().password.clone().unwrap();
let login_ref = login.read();
let homeserver_url = login_ref.homeserver_url.clone().unwrap();
let username = login_ref.email.clone().unwrap();
let password = login_ref.password.clone().unwrap();
async move {
let requester = MatrixClient::spawn(homeserver_url, store).await;
let requester = MatrixClient::spawn(homeserver_url, arc_store.clone()).await;
requester.init();
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! {
style { STYLE_SHEET },
@@ -83,7 +86,7 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
id: "input-homeserver-url",
r#type: "text",
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()),
},
@@ -94,7 +97,7 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
id: "login-input-email",
r#type: "text",
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()),
},
p {
@@ -105,7 +108,7 @@ pub fn Login<'a>(cx: Scope<'a, LoginProps<'a>>) -> Element<'a> {
id: "login-input-password",
r#type: "password",
name: "Password",
value: "{login.read().password.as_ref().unwrap_or(&empty_placeholder)}",
value: "{password_value}",
oninput: move |evt| {
login.write().password = Some(evt.value.clone());
invalid_login.set(false);

View File

@@ -1,6 +1,4 @@
pub mod avatar_selector;
pub mod contacts;
pub mod contacts_window;
pub mod header;
pub mod login;
pub mod user_infos;

View File

@@ -1,4 +1,5 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus_desktop::Config;
use dioxus_std::utils::rw::use_rw;
@@ -7,7 +8,7 @@ pub mod components;
pub mod matrix_client;
use crate::base::{AppSettings, Store};
use crate::components::contacts_window::ContactWindow;
use crate::components::contacts_window::contacts_window::ContactsWindow;
use crate::components::login::Login;
mod base;
@@ -15,16 +16,16 @@ mod base;
fn App(cx: Scope<AppSettings>) -> Element {
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! {
if is_logged {
rsx!(ContactWindow {})
rsx!(ContactsWindow {rw_store: rw_store})
}
else {
rsx!(Login {store: store})
rsx!(Login {rw_store: rw_store})
}
})
}

View File

@@ -1,18 +1,42 @@
use std::fmt::{Debug, Formatter};
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 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::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)]
pub enum LoginStyle {
@@ -78,7 +102,7 @@ fn oneshot<T>() -> (ClientReply<T>, ClientResponse<T>) {
#[derive(Debug)]
pub struct Requester {
pub client: Client,
pub client: Arc<Client>,
pub tx: UnboundedSender<WorkerTask>,
}
@@ -106,35 +130,42 @@ impl Requester {
pub struct MatrixClient {
initialized: bool,
client: Option<Arc<Client>>,
client: Arc<Client>,
// sync_token: Option<String>,
// load_handle: Option<JoinHandle<()>>,
load_handle: Option<JoinHandle<()>>,
sync_handle: Option<JoinHandle<()>>,
store: UseRw<Store>,
store: ReactiveStore,
}
impl MatrixClient {
pub async fn spawn(homeserver_url: String, store: UseRw<Store>) -> Requester {
let (tx, rx) = unbounded_channel::<WorkerTask>();
let client = Client::builder()
.homeserver_url(&homeserver_url)
.build()
.await
.unwrap();
let mut matrix_client = MatrixClient {
client: None,
fn new(store: ReactiveStore, client: Arc<Client>) -> Self {
Self {
client: client,
initialized: false,
// sync_token: None,
// load_handle: None,
load_handle: None,
sync_handle: None,
store: store,
};
matrix_client.client = Some(Arc::new(client.clone()));
}
}
tokio::spawn(async move {
matrix_client.work(rx).await;
pub async fn spawn(homeserver_url: String, store: ReactiveStore) -> Requester {
let (tx, rx) = unbounded_channel::<WorkerTask>();
let client = Arc::new(
Client::builder()
.homeserver_url(&homeserver_url)
.build()
.await
.unwrap(),
);
let mut matrix_client = MatrixClient::new(store, client.clone());
tokio::spawn({
async move {
matrix_client.work(rx).await;
}
});
Requester { client, tx }
@@ -176,27 +207,289 @@ impl MatrixClient {
}
}
async fn on_sync_event(_ev: SyncTypingEvent, room: MatrixRoom) {
println!("== on_sync_event ==");
async fn on_sync_typing_event(
_ev: SyncTypingEvent,
room: MatrixRoom,
_store: Ctx<ReactiveStore>,
) {
println!("== on_sync_typing_event ==");
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 ==");
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) {
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_event);
let _ = client.add_event_handler(MatrixClient::on_sync_typing_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<()> {
let client = self.client.clone().unwrap();
let client = self.client.clone();
match style {
LoginStyle::Password(username, password) => {
@@ -210,22 +503,24 @@ impl MatrixClient {
}
}
self.sync_handle = tokio::spawn(async move {
// Sync once so we receive the client state and old messages
let _ret = client.sync_once(SyncSettings::default()).await;
self.load_user_infos().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 {
let settings = SyncSettings::default();
let _ = client.sync(settings).await;
loop {
let settings = SyncSettings::default();
let _ = client.sync(settings).await;
}
}
})
.into();
let mut store = self.store.read().unwrap().to_owned();
store.is_logged = true;
let _ = self.store.write(store).unwrap();
let _ = self.store.write(store);
println!("User connected to the homeserver");
Ok(())