diff options
author | 2025-06-01 16:10:26 +0100 | |
---|---|---|
committer | 2025-06-01 17:27:40 +0100 | |
commit | 6ee4190a26f32bfa953302ee363ad3bb6c384ebb (patch) | |
tree | 2c3182c29d5780a0ad9c9770b5e546312bea49b4 /src/views/macaw.rs | |
parent | f76c80c1d23177ab00c81240ee3a75d3bcda0e3b (diff) | |
download | macaw-web-6ee4190a26f32bfa953302ee363ad3bb6c384ebb.tar.gz macaw-web-6ee4190a26f32bfa953302ee363ad3bb6c384ebb.tar.bz2 macaw-web-6ee4190a26f32bfa953302ee363ad3bb6c384ebb.zip |
refactor: reorganise code
Diffstat (limited to 'src/views/macaw.rs')
-rw-r--r-- | src/views/macaw.rs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/views/macaw.rs b/src/views/macaw.rs new file mode 100644 index 0000000..18e0ad3 --- /dev/null +++ b/src/views/macaw.rs @@ -0,0 +1,162 @@ +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::MacawContact, message::MacawMessage, message_subscriptions::MessageSubscriptions, open_chats::OpenChatsPanel, roster::{Roster, RosterStoreFields}, state_store::StateStore, user::MacawUser, user_presences::{Presences, UserPresences}}; + +use super::AppState; + +pub mod settings; +mod open_chats_panel; + +#[component] +pub fn Macaw( + // TODO: logout + // app_state: WriteSignal<Option<essage>)>, LocalStorage>, + client: Client, + mut updates: Receiver<UpdateMessage>, + set_app: WriteSignal<AppState>, +) -> 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<Uuid, ArcStore<Message>> = StateStore::new(); + provide_context(messages_store); + let chats_store: StateStore<BareJID, ArcStore<Chat>> = StateStore::new(); + provide_context(chats_store); + let users_store: StateStore<BareJID, ArcStore<User>> = StateStore::new(); + provide_context(users_store); + + let open_chats = Store::new(OpenChatsPanel::default()); + provide_context(open_chats); + let show_settings = RwSignal::new(None::<SettingsPage>); + provide_context(show_settings); + + let user_presences = Store::new(UserPresences::new()); + provide_context(user_presences); + + let client_user = LocalResource::new(move || { + async move { + let client = use_context::<Client>().expect("client not in context"); + let user = client.get_user((*client.jid).clone()).await.unwrap(); + MacawUser::got_user(user) + } + }); + provide_context(client_user); + + // TODO: timestamp incoming/outgoing subscription requests + let (subscription_requests, set_subscription_requests)= signal(HashSet::<BareJID>::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(), + MacawContact::got_contact_and_user(contact, user), + ) + }) + .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 = MacawContact::got_contact_and_user(contact, user); + 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().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 = MacawMessage::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| { + <ArcStore<filamento::chat::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! { + <Sidebar /> + // <ChatsList /> + <OpenChatsPanelView /> + {move || if let Some(_) = *show_settings.read() { + view! { <Settings /> }.into_any() + } else { + view! {}.into_any() + }} + } +} + |