// Cf. https://dioxuslabs.com/learn/0.4/reference/use_coroutine // In order to use/run the rx.next().await statement you will need to extend the [Stream] trait // (used by [UnboundedReceiver]) by adding 'futures_util' as a dependency to your project // and adding the use futures_util::stream::StreamExt; use futures_util::stream::StreamExt; use std::{collections::HashMap, sync::Arc}; use dioxus::prelude::*; use fermi::*; use matrix_sdk::room::Room as MatrixRoom; use matrix_sdk::{ room::RoomMember, ruma::{OwnedRoomId, OwnedUserId}, }; use tokio::select; use tracing::{debug, error, warn}; use crate::components::chats_window::interface::Interface as ChatsWinInterface; use crate::matrix_interface::client::{Client, RoomTopicEvent}; use crate::matrix_interface::requester::{Receivers, Requester}; use crate::matrix_interface::worker_tasks::LoginStyle; // #[derive(Clone, Debug)] // pub struct UserInfo { // pub avatar_url: Option, // pub display_name: Option, // pub blurhash: Option, // } // impl UserInfo { // pub fn new( // avatar_url: Option, // display_name: Option, // blurhash: Option, // ) -> Self { // Self { // avatar_url, // display_name, // blurhash, // } // } // } #[derive(Clone)] pub struct Room { pub matrix_room: Arc, pub topic: Option>, pub members: HashMap, pub is_direct: Option, } impl Room { pub fn new( matrix_room: Arc, topic: Option>, is_direct: Option, ) -> Self { Self { matrix_room, topic, members: HashMap::new(), is_direct, } } pub fn name(&self) -> Option { self.matrix_room.name() } pub fn id(&self) -> OwnedRoomId { OwnedRoomId::from(self.matrix_room.room_id()) } } 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() } } pub type ByIdRooms = HashMap>; // pub type ByIdUserInfos = HashMap; // #[derive(Clone)] // pub struct Store { // pub is_logged: bool, // pub rooms: ByIdRooms, // pub user_infos: ByIdUserInfos, // pub user_id: Option, // } // impl 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 struct AppSettings { pub requester: Option>, } impl AppSettings { pub fn new() -> Self { Self { requester: None } } pub fn set_requester(&mut self, requester: RefCell) { self.requester = Some(requester); } } pub static APP_SETTINGS: AtomRef = AtomRef(|_| AppSettings::new()); async fn on_room(room: Room, rooms_ref: &UseAtomRef) { let room_id = room.id(); // TODO: Update rooms rooms_ref .write() .insert(room_id, RefCell::::new(room)); } pub async fn on_room_topic(room_topic_event: RoomTopicEvent, rooms_ref: &UseAtomRef) { let room_id = room_topic_event.0; if let Some(room_ref) = rooms_ref.read().get(&room_id) { let topic = room_topic_event.1; let mut room = room_ref.borrow_mut(); room.topic = Some(RefCell::new(topic)); } else { warn!("No room found with the \"{}\" id", room_id); } } pub async fn sync_rooms( mut rx: UnboundedReceiver, receivers: Receivers, rooms_ref: UseAtomRef, ) { if let Some(_is_logged) = rx.next().await { let mut rooms_receiver = receivers.rooms_receiver.borrow_mut(); let mut room_topic_receiver = receivers.room_topic_receiver.borrow_mut(); loop { select! { res = rooms_receiver.recv() => { if let Ok(room) = res { on_room(room, &rooms_ref).await; } }, res = room_topic_receiver.recv() => { if let Ok(room_topic_event) = res { on_room_topic(room_topic_event, &rooms_ref).await; } } } } } } pub async fn login( mut rx: UnboundedReceiver, app_settings_ref: UseAtomRef, session_ref: UseAtomRef, ) { while let Some(is_logged) = rx.next().await { if !is_logged { let homeserver_url = session_ref.read().homeserver_url.clone(); let username = session_ref.read().username.clone(); let password = session_ref.read().password.clone(); if homeserver_url.is_some() && username.is_some() && password.is_some() { let client = Client::spawn(homeserver_url.unwrap()).await; client.init().await; match client .login(LoginStyle::Password(username.unwrap(), password.unwrap())) .await { Ok(_) => { debug!("successfully logged"); session_ref.write().is_logged = true; } Err(err) => { error!("Error during login: {err}"); // invalid_login.modify(|_| true); } } app_settings_ref.write().set_requester(RefCell::new(client)); } else { warn!("At least one of the following values is/are invalid: homeserver, username or password"); } } else { warn!("already logged... skip login"); } } error!("=== LOGIN END ==="); } pub struct Session { pub homeserver_url: Option, pub username: Option, pub password: Option, pub is_logged: bool, } impl Session { fn new() -> Self { Self { homeserver_url: None, username: None, password: None, is_logged: false, } } pub fn update( &mut self, homeserver_url: Option, username: Option, password: Option, ) { self.homeserver_url = homeserver_url; self.username = username; self.password = password; } } pub static ROOMS: AtomRef = AtomRef(|_| ByIdRooms::new()); pub static SESSION: AtomRef = AtomRef(|_| Session::new()); pub static CHATS_WIN_INTERFACE: AtomRef = AtomRef(|_| ChatsWinInterface::new());