diff options
author | 2025-06-01 16:10:26 +0100 | |
---|---|---|
committer | 2025-06-01 17:27:40 +0100 | |
commit | 6ee4190a26f32bfa953302ee363ad3bb6c384ebb (patch) | |
tree | 2c3182c29d5780a0ad9c9770b5e546312bea49b4 /src/components/message_history_buffer.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/components/message_history_buffer.rs')
-rw-r--r-- | src/components/message_history_buffer.rs | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/components/message_history_buffer.rs b/src/components/message_history_buffer.rs new file mode 100644 index 0000000..36439a8 --- /dev/null +++ b/src/components/message_history_buffer.rs @@ -0,0 +1,176 @@ +use chrono::{NaiveDateTime, TimeDelta}; +use filamento::{chat::{Chat, ChatStoreFields, MessageStoreFields}, user::User}; +use indexmap::IndexMap; +use jid::BareJID; +use leptos::prelude::*; +use reactive_stores::{ArcStore, Store}; +use tracing::{debug, error}; +use uuid::Uuid; + +use crate::{chat::MacawChat, client::Client, components::message::Message, message::MacawMessage, message_subscriptions::MessageSubscriptions}; + +#[component] +pub fn MessageHistoryBuffer(chat: MacawChat) -> impl IntoView { + let (messages, set_messages) = arc_signal(IndexMap::new()); + let chat_chat: Store<Chat> = + <ArcStore<filamento::chat::Chat> as Clone>::clone(&chat.chat).into(); + let chat_user: Store<User> = + <ArcStore<filamento::user::User> as Clone>::clone(&chat.user).into(); + + let load_set_messages = set_messages.clone(); + let load_messages = LocalResource::new(move || { + let load_set_messages = load_set_messages.clone(); + async move { + let client = use_context::<Client>().expect("client not in context"); + let messages = client + .get_messages_with_users(chat_chat.correspondent().get()) + .await + .map_err(|e| e.to_string()); + match messages { + Ok(m) => { + let messages = m + .into_iter() + .map(|(message, message_user)| { + ( + message.id, + MacawMessage::got_message_and_user(message, message_user), + ) + }) + .collect::<IndexMap<Uuid, _>>(); + load_set_messages.set(messages); + } + Err(err) => { + error!("{err}") + // TODO: show error message at top of chats list + } + } + } + }); + + // TODO: filter new messages signal + let new_messages_signal: RwSignal<MessageSubscriptions> = use_context().unwrap(); + let (sub_id, set_sub_id) = signal(None); + let load_new_messages_set = set_messages.clone(); + let _load_new_messages = LocalResource::new(move || { + let load_new_messages_set = load_new_messages_set.clone(); + async move { + load_messages.await; + let (sub_id, mut new_messages) = new_messages_signal + .write() + .subscribe_chat(chat_chat.correspondent().get()); + set_sub_id.set(Some(sub_id)); + while let Some(new_message) = new_messages.recv().await { + debug!("got new message in let message buffer"); + let mut messages = load_new_messages_set.write(); + if let Some((_, last)) = messages.last() { + if *<ArcStore<filamento::chat::Message> as Clone>::clone(&last.message) + .timestamp() + .read() + < *<ArcStore<filamento::chat::Message> as Clone>::clone(&new_message.message) + .timestamp() + .read() + { + messages.insert( + <ArcStore<filamento::chat::Message> as Clone>::clone( + &new_message.message, + ) + .id() + .get(), + new_message, + ); + debug!("set the new message in message buffer"); + } else { + let index = match messages.binary_search_by(|_, value| { + <ArcStore<filamento::chat::Message> as Clone>::clone(&value.message) + .timestamp() + .read() + .cmp( + &<ArcStore<filamento::chat::Message> as Clone>::clone( + &new_message.message, + ) + .timestamp() + .read(), + ) + }) { + Ok(i) => i, + Err(i) => i, + }; + messages.insert_before( + // TODO: check if this logic is correct + index, + <ArcStore<filamento::chat::Message> as Clone>::clone( + &new_message.message, + ) + .id() + .get(), + new_message, + ); + debug!("set the new message in message buffer"); + } + } else { + messages.insert( + <ArcStore<filamento::chat::Message> as Clone>::clone(&new_message.message) + .id() + .get(), + new_message, + ); + debug!("set the new message in message buffer"); + } + } + } + }); + on_cleanup(move || { + if let Some(sub_id) = sub_id.get() { + new_messages_signal + .write() + .unsubscribe_chat(sub_id, chat_chat.correspondent().get()); + } + }); + + let each = move || { + let mut last_timestamp = NaiveDateTime::MIN; + let mut last_user: Option<BareJID> = None; + let mut messages = messages + .get() + .into_iter() + .map(|(id, message)| { + let message_timestamp = + <ArcStore<filamento::chat::Message> as Clone>::clone(&message.message) + .timestamp() + .read() + .naive_local(); + // TODO: mark new day + // if message_timestamp.date() > last_timestamp.date() { + // messages_view = messages_view.push(date(message_timestamp.date())); + // } + let major = if last_user.as_ref() != Some(&message.message.read().from) + || message_timestamp - last_timestamp > TimeDelta::minutes(3) + { + true + } else { + false + }; + last_user = Some( + <ArcStore<filamento::chat::Message> as Clone>::clone(&message.message) + .from() + .get(), + ); + last_timestamp = message_timestamp; + (id, (message, major, false)) + }) + .collect::<Vec<_>>(); + if let Some((_id, (_, _, last))) = messages.last_mut() { + *last = true + } + messages.into_iter().rev() + }; + + view! { + <div class="messages-buffer"> + <For each=each key=|message| (message.0, message.1.1, message.1.2) let(message)> + <Message message=message.1.0 major=message.1.1 r#final=message.1.2 /> + </For> + </div> + } +} + |