summaryrefslogblamecommitdiffstats
path: root/src/views/macaw.rs
blob: e6ec66c2eaa244bf328c19c2888f55bf18831286 (plain) (tree)
1
2
3
4
5
6

                              
                                                                                                         

                                            
                              






                                         
                                                                                                                                                                                                                                                                                   





                     











                                                                      
















                                                                           

                                                     





























































                                                                                                               
                                                                                                            























                                                                                                                




                                                                                                                         




                                                                                 




                                                                                                     

                                                             




                                                                                                     
















                                                         
use std::collections::HashSet;

use filamento::{chat::{Chat, Message, MessageStoreFields}, user::{User, UserStoreFields}, UpdateMessage};
use jid::BareJID;
use leptos::{prelude::*, task::spawn_local};
use leptos_fetch::QueryClient;
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}, user::MacawUser, user_presences::{Presences, UserPresences}};

use super::AppState;

pub mod settings;
mod open_chats_panel;

// TODO: remove
async fn get_message(id: Uuid) -> ArcStore<Message> {
    let client: Client = use_context().expect("no client in context");
    ArcStore::new(client.get_message(id).await.unwrap())
}

async fn get_user(jid: BareJID) -> ArcStore<User> {
    let client: Client = use_context().expect("no client in context");
    ArcStore::new(client.get_user(jid).await.unwrap())
}


#[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);

    QueryClient::new().provide();
    let query_client: QueryClient = expect_context();

    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_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 = 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 } => {
                    query_client.update_query(get_message, id, |message| {
                        if let Some(message) = 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 } => {
                    query_client.update_query(get_user, jid, |user| {
                        if let Some(user) = user {
                            <ArcStore<filamento::user::User> as Clone>::clone(&user).nick().set(nick)
                        }
                    })
                }
                UpdateMessage::AvatarChanged { jid, id } => {
                    query_client.update_query(get_user, jid, |user| {
                        if let Some(user) = user {
                            <ArcStore<filamento::user::User> as Clone>::clone(&user).avatar().set(id)
                        }
                    })
                }
            }
        }
    });

    view! {
        <Sidebar />
        // <ChatsList />
        <OpenChatsPanelView />
        {move || if let Some(_) = *show_settings.read() {
            view! { <Settings /> }.into_any()
        } else {
            view! {}.into_any()
        }}
    }
}