Files
beau-gosse-du-92/src/base.rs
Adrien 116bbcb247 🚧 Add an interface to the ChatsWindows to drive its behavior
For now, only the ChatsWindow tabs are toggled on clicks on room names (from ContactsSection).
2023-12-30 23:31:51 +01:00

254 lines
7.3 KiB
Rust

// 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<OwnedMxcUri>,
// pub display_name: Option<String>,
// pub blurhash: Option<String>,
// }
// 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)]
pub struct Room {
pub matrix_room: Arc<MatrixRoom>,
pub topic: Option<RefCell<String>>,
pub members: HashMap<OwnedUserId, RoomMember>,
pub is_direct: Option<bool>,
}
impl Room {
pub fn new(
matrix_room: Arc<MatrixRoom>,
topic: Option<RefCell<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()
}
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<OwnedRoomId, RefCell<Room>>;
// pub type ByIdUserInfos = HashMap<OwnedUserId, UserInfo>;
// #[derive(Clone)]
// pub struct Store {
// pub is_logged: bool,
// pub rooms: ByIdRooms,
// pub user_infos: ByIdUserInfos,
// pub user_id: Option<OwnedUserId>,
// }
// 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<RefCell<Requester>>,
}
impl AppSettings {
pub fn new() -> Self {
Self { requester: None }
}
pub fn set_requester(&mut self, requester: RefCell<Requester>) {
self.requester = Some(requester);
}
}
pub static APP_SETTINGS: AtomRef<AppSettings> = AtomRef(|_| AppSettings::new());
async fn on_room(room: Room, rooms_ref: &UseAtomRef<ByIdRooms>) {
let room_id = room.id();
// TODO: Update rooms
rooms_ref
.write()
.insert(room_id, RefCell::<Room>::new(room));
}
pub async fn on_room_topic(room_topic_event: RoomTopicEvent, rooms_ref: &UseAtomRef<ByIdRooms>) {
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<bool>,
receivers: Receivers,
rooms_ref: UseAtomRef<ByIdRooms>,
) {
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<bool>,
app_settings_ref: UseAtomRef<AppSettings>,
session_ref: UseAtomRef<Session>,
) {
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<String>,
pub username: Option<String>,
pub password: Option<String>,
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<String>,
username: Option<String>,
password: Option<String>,
) {
self.homeserver_url = homeserver_url;
self.username = username;
self.password = password;
}
}
pub static ROOMS: AtomRef<ByIdRooms> = AtomRef(|_| ByIdRooms::new());
pub static SESSION: AtomRef<Session> = AtomRef(|_| Session::new());
pub static CHATS_WIN_INTERFACE: AtomRef<ChatsWinInterface> = AtomRef(|_| ChatsWinInterface::new());