use std::collections::HashSet; use filamento::{chat::{Chat, Message, MessageStoreFields}, user::User, UpdateMessage}; use jid::BareJID; use leptos::{prelude::*, task::spawn_local}; use open_chats_panel::OpenChatsPanelView; use reactive_stores::{ArcStore, Store}; use settings::{Settings, SettingsPage}; use tokio::sync::mpsc::Receiver; use tracing::debug; use uuid::Uuid; use crate::{client::Client, components::sidebar::Sidebar, contact::{ArcMacawContact, MacawContact}, message::{ArcMacawMessage, MacawMessage}, message_subscriptions::MessageSubscriptions, open_chats::OpenChatsPanel, roster::{Roster, RosterStoreFields}, state_store::StateStore, user::{ArcMacawUser, MacawUser}, user_presences::{Presences, UserPresences}}; use super::AppState; pub mod settings; mod open_chats_panel; #[component] pub fn Macaw( // TODO: logout // app_state: WriteSignal)>, LocalStorage>, client: Client, mut updates: Receiver, set_app: WriteSignal, ) -> impl IntoView { provide_context(set_app); provide_context(client); let roster = Store::new(Roster::new()); provide_context(roster); let message_subscriptions = RwSignal::new(MessageSubscriptions::new()); provide_context(message_subscriptions); let messages_store: StateStore> = StateStore::new(); provide_context(messages_store); let chats_store: StateStore> = StateStore::new(); provide_context(chats_store); let users_store: StateStore> = StateStore::new(); provide_context(users_store); let open_chats = Store::new(OpenChatsPanel::default()); provide_context(open_chats); let show_settings = RwSignal::new(None::); provide_context(show_settings); let user_presences = Store::new(UserPresences::new()); provide_context(user_presences); let client_user: LocalResource = LocalResource::new(move || { async move { let client = use_context::().expect("client not in context"); let user = client.get_user((*client.jid).clone()).await.unwrap(); ArcMacawUser::got_user(user).into() } }); provide_context(client_user); // TODO: timestamp incoming/outgoing subscription requests let (subscription_requests, set_subscription_requests)= signal(HashSet::::new()); provide_context(subscription_requests); provide_context(set_subscription_requests); // TODO: get cached contacts on login before getting the updated contacts OnceResource::new(async move { while let Some(update) = updates.recv().await { match update { UpdateMessage::Online(online, items) => { let contacts = items .into_iter() .map(|(contact, user)| { ( contact.user_jid.clone(), ArcMacawContact::got_contact_and_user(contact, user).into(), ) }) .collect(); roster.contacts().set(contacts); } UpdateMessage::Offline(offline) => { // when offline, will no longer receive updated user presences, consider everybody offline. user_presences.write().clear(); } UpdateMessage::RosterUpdate(contact, user) => { roster.contacts().update(|roster| { if let Some(macaw_contact) = roster.get_mut(&contact.user_jid) { macaw_contact.set(contact); } else { let jid = contact.user_jid.clone(); let contact = ArcMacawContact::got_contact_and_user(contact, user).into(); roster.insert(jid, contact); } }); } UpdateMessage::RosterDelete(jid) => { roster.contacts().update(|roster| { roster.remove(&jid); }); } UpdateMessage::Presence { from, presence } => { let bare_jid = from.to_bare(); if let Some(presences) = user_presences.read_untracked().user_presences.get(&bare_jid) { if let Some(resource) = from.resourcepart() { presences.write().update_presence(resource.clone(), presence); } } else { if let Some(resource) = from.resourcepart() { let mut presences = Presences::new(); presences.update_presence(resource.clone(), presence); user_presences.write().user_presences.insert(bare_jid, ArcRwSignal::new(presences)); } } } UpdateMessage::Message { to, from, message } => { debug!("before got message"); let new_message = ArcMacawMessage::got_message_and_user(message, from); debug!("after got message"); spawn_local(async move { message_subscriptions .write() .broadcast(to, new_message) .await }); debug!("after set message"); } UpdateMessage::MessageDelivery { id, chat, delivery } => { messages_store.modify(&id, |message| { as Clone>::clone(&message).delivery() .set(Some(delivery)) }); } UpdateMessage::SubscriptionRequest(jid) => { set_subscription_requests.update(|req| { req.insert(jid); }); } UpdateMessage::NickChanged { jid, nick } => { users_store.modify(&jid, |user| { user.update(|user| *&mut user.nick = nick.clone()) }); } UpdateMessage::AvatarChanged { jid, id } => { users_store.modify(&jid, |user| *&mut user.write().avatar = id.clone()); } } } }); view! { // {move || if let Some(_) = *show_settings.read() { view! { }.into_any() } else { view! {}.into_any() }} } }