diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 27417e4..373c35a 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -107,47 +107,62 @@ async fn main() { subscription_id, } = message { - if event.kind == Kind::GiftWrap { - match client.unwrap_gift_wrap(&event).await { - Ok(UnwrappedGift { mut rumor, sender }) => { - // Request metadata - if let Err(e) = mta_tx.send(sender).await { - println!("Send error: {}", e) - }; + match event.kind { + Kind::GiftWrap => { + match client.unwrap_gift_wrap(&event).await { + Ok(UnwrappedGift { mut rumor, sender }) => { + // Request metadata + if let Err(e) = mta_tx.send(sender).await { + println!("Send error: {}", e) + }; - // Compute event id if not exist - rumor.ensure_id(); + // Compute event id if not exist + rumor.ensure_id(); - if let Some(id) = rumor.id { - let ev = Event::new( - id, - rumor.pubkey, - rumor.created_at, - rumor.kind, - rumor.tags, - rumor.content, - sig, - ); + if let Some(id) = rumor.id { + let ev = Event::new( + id, + rumor.pubkey, + rumor.created_at, + rumor.kind, + rumor.tags, + rumor.content, + sig, + ); - // Save rumor to database to further query - if let Err(e) = client.database().save_event(&ev).await { - println!("Save error: {}", e); - } + // Save rumor to database to further query + if let Err(e) = client.database().save_event(&ev).await { + println!("Save error: {}", e); + } - // Send event back to channel - if subscription_id == new_message { - if let Err(e) = signal_tx.send(Signal::Event(ev)).await { - println!("Send error: {}", e) + // Send event back to channel + if subscription_id == new_message { + if let Err(e) = signal_tx.send(Signal::Event(ev)).await + { + println!("Send error: {}", e) + } } } } + Err(e) => println!("Unwrap error: {}", e), } - Err(e) => println!("Unwrap error: {}", e), } - } else if event.kind == Kind::Metadata { - if let Err(e) = signal_tx.send(Signal::Metadata(event.pubkey)).await { - println!("Send error: {}", e) + Kind::ContactList => { + let public_keys: Vec = + event.tags.public_keys().copied().collect(); + + for public_key in public_keys.into_iter() { + if let Err(e) = mta_tx.send(public_key).await { + println!("Send error: {}", e) + }; + } } + Kind::Metadata => { + if let Err(e) = signal_tx.send(Signal::Metadata(event.pubkey)).await { + println!("Send error: {}", e) + } + } + _ => {} } } else if let RelayMessage::EndOfStoredEvents(subscription_id) = message { if subscription_id == all_messages { @@ -283,8 +298,8 @@ async fn main() { }) .await; - _ = async_cx.update_global::(|state, _cx| { - state.new_message(event, metadata) + _ = async_cx.update_global::(|state, cx| { + state.new_message(event, metadata, cx) }); } } diff --git a/crates/app/src/states/chat.rs b/crates/app/src/states/chat.rs index af1dda1..35b3f16 100644 --- a/crates/app/src/states/chat.rs +++ b/crates/app/src/states/chat.rs @@ -1,6 +1,6 @@ use crate::get_client; use crate::utils::get_room_id; -use gpui::{AppContext, Context, Global, Model, SharedString}; +use gpui::{AppContext, Context, Global, Model, SharedString, WeakModel}; use itertools::Itertools; use nostr_sdk::prelude::*; use rnglib::{Language, RNG}; @@ -76,10 +76,11 @@ impl Message { } } +type Messages = RwLock>>>>; + pub struct ChatRegistry { - pub messages: RwLock>>>>, - pub rooms: Model>, - pub is_initialized: bool, + messages: Model, + rooms: Model>, } impl Global for ChatRegistry {} @@ -87,13 +88,9 @@ impl Global for ChatRegistry {} impl ChatRegistry { pub fn set_global(cx: &mut AppContext) { let rooms = cx.new_model(|_| Vec::new()); - let messages = RwLock::new(HashMap::new()); + let messages = cx.new_model(|_| RwLock::new(HashMap::new())); - cx.set_global(Self { - messages, - rooms, - is_initialized: false, - }); + cx.set_global(Self { messages, rooms }); } pub fn init(&mut self, cx: &mut AppContext) { @@ -143,31 +140,36 @@ impl ChatRegistry { model.extend(events); cx.notify(); }); - - state.is_initialized = true; }); } }) .detach(); } - pub fn new_message(&mut self, event: Event, metadata: Option) { + pub fn new_message(&mut self, event: Event, metadata: Option, cx: &mut AppContext) { // Get room id let room_id = SharedString::from(get_room_id(&event.pubkey, &event.tags)); // Create message let message = Message::new(event, metadata); - self.messages - .write() - .unwrap() - .entry(room_id) - .or_insert(Arc::new(RwLock::new(Vec::new()))) - .write() - .unwrap() - .push(message) + self.messages.update(cx, |this, cx| { + this.write() + .unwrap() + .entry(room_id) + .or_insert(Arc::new(RwLock::new(Vec::new()))) + .write() + .unwrap() + .push(message); + + cx.notify(); + }); } - pub fn get_messages(&self, id: &SharedString) -> Option>>> { - self.messages.read().unwrap().get(id).cloned() + pub fn messages(&self) -> WeakModel { + self.messages.downgrade() + } + + pub fn rooms(&self) -> WeakModel> { + self.rooms.downgrade() } } diff --git a/crates/app/src/views/chat/room.rs b/crates/app/src/views/chat/room.rs index 351ba29..e4002fc 100644 --- a/crates/app/src/views/chat/room.rs +++ b/crates/app/src/views/chat/room.rs @@ -166,39 +166,42 @@ impl RoomPanel { pub fn subscribe(&self, cx: &mut ViewContext) { let room_id = self.id.clone(); let messages = self.messages.clone(); + let state = cx.global::().messages(); - cx.observe_global::(move |_, cx| { - let state = cx.global::(); - let new_messages = state.get_messages(&room_id); + if let Some(state) = state.upgrade() { + cx.observe(&state, move |_, model, cx| { + let new_messages = model.read(cx).read().unwrap().get(&room_id).cloned(); - if let Some(new_messages) = new_messages { - let items: Vec = new_messages - .read() - .unwrap() - .clone() - .into_iter() - .map(|m| { - RoomMessage::new( - m.event.pubkey, - m.metadata, - m.event.content, - m.event.created_at, - ) - }) - .collect(); + if let Some(new_messages) = new_messages { + let items: Vec = new_messages + .read() + .unwrap() + .clone() + .into_iter() + .map(|m| { + RoomMessage::new( + m.event.pubkey, + m.metadata, + m.event.content, + m.event.created_at, + ) + }) + .collect(); - cx.update_model(&messages, |model, cx| { - model.items.extend(items); - model.count = model.items.len(); - cx.notify(); - }); - } - }) - .detach(); + cx.update_model(&messages, |model, cx| { + model.items.extend(items); + model.count = model.items.len(); + cx.notify(); + }); + } + }) + .detach(); + } } fn send_message(&mut self, cx: &mut ViewContext) { - let owner = self.owner; + let members = self.members.clone(); + let members2 = members.clone(); let content = self.input.read(cx).text().to_string(); let content2 = content.clone(); let content3 = content2.clone(); @@ -223,20 +226,40 @@ impl RoomPanel { // Send message to all members async_cx .background_executor() - .spawn(async move { client.send_private_msg(owner, content, vec![]).await }) + .spawn(async move { + for member in members.iter() { + let tags: Vec = members + .iter() + .filter_map(|public_key| { + if public_key != member { + Some(Tag::public_key(*public_key)) + } else { + None + } + }) + .collect(); + + _ = client.send_private_msg(*member, &content, tags).await; + } + }) .detach(); // Send a copy to yourself async_cx .background_executor() .spawn(async move { - client - .send_private_msg( - current_user, - content2, - vec![Tag::public_key(owner)], - ) - .await + let tags: Vec = members2 + .iter() + .filter_map(|public_key| { + if public_key != ¤t_user { + Some(Tag::public_key(*public_key)) + } else { + None + } + }) + .collect(); + + _ = client.send_private_msg(current_user, content2, tags).await; }) .detach(); diff --git a/crates/app/src/views/sidebar/contact_list.rs b/crates/app/src/views/sidebar/contact_list.rs index e2e76fb..397336a 100644 --- a/crates/app/src/views/sidebar/contact_list.rs +++ b/crates/app/src/views/sidebar/contact_list.rs @@ -191,7 +191,7 @@ impl ContactList { } } - pub fn _selected(&self) -> Vec { + pub fn selected(&self) -> Vec { self.selected.clone().into_iter().collect() } diff --git a/crates/app/src/views/sidebar/inbox.rs b/crates/app/src/views/sidebar/inbox.rs index e71ed06..f37594b 100644 --- a/crates/app/src/views/sidebar/inbox.rs +++ b/crates/app/src/views/sidebar/inbox.rs @@ -165,13 +165,14 @@ pub struct Inbox { impl Inbox { pub fn new(cx: &mut ViewContext<'_, Self>) -> Self { let items = cx.new_model(|_| None); + let events = cx.global::().rooms(); - cx.observe_global::(|this, cx| { - if cx.global::().is_initialized { - this.load(cx) - } - }) - .detach(); + if let Some(events) = events.upgrade() { + cx.observe(&events, |this, model, cx| { + this.load(model, cx); + }) + .detach(); + } Self { items, @@ -181,9 +182,8 @@ impl Inbox { } } - pub fn load(&mut self, cx: &mut ViewContext) { - // Get all room's events - let events: Vec = cx.global::().rooms.read(cx).clone(); + pub fn load(&mut self, model: Model>, cx: &mut ViewContext) { + let events = model.read(cx).clone(); cx.spawn(|view, mut async_cx| async move { let client = get_client(); diff --git a/crates/app/src/views/sidebar/mod.rs b/crates/app/src/views/sidebar/mod.rs index 25efcf4..e9e3f9d 100644 --- a/crates/app/src/views/sidebar/mod.rs +++ b/crates/app/src/views/sidebar/mod.rs @@ -36,7 +36,7 @@ impl Sidebar { let inbox = cx.new_view(Inbox::new); Self { - name: "Left Dock".into(), + name: "Sidebar".into(), closeable: true, zoomable: true, focus_handle: cx.focus_handle(), @@ -57,9 +57,9 @@ impl Sidebar { .rounded(ButtonRounded::Large) .w_full() .on_click({ - let _contact_list = contact_list.clone(); - move |_, _cx| { - // TODO: open room + let contact_list = contact_list.clone(); + move |_, cx| { + let _selected = contact_list.model.read(cx).selected(); } }), ),