summaryrefslogtreecommitdiffstats
path: root/src/views/macaw.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/views/macaw.rs')
-rw-r--r--src/views/macaw.rs162
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()
+ }}
+ }
+}
+