chore: refactor message sending (#172)
* refactor send message * refactor resend * fix * refactor * clean up
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::time::Duration;
|
||||
|
||||
use common::display::{RenderedProfile, RenderedTimestamp};
|
||||
use common::nip96::nip96_upload;
|
||||
@@ -99,7 +100,7 @@ impl Chat {
|
||||
let messages = BTreeSet::from([Message::system()]);
|
||||
let list_state = ListState::new(messages.len(), ListAlignment::Bottom, px(1024.));
|
||||
|
||||
let connect_relays = room.read(cx).connect_relays(cx);
|
||||
let connect = room.read(cx).connect(cx);
|
||||
let load_messages = room.read(cx).load_messages(cx);
|
||||
|
||||
let mut subscriptions = smallvec![];
|
||||
@@ -108,43 +109,41 @@ impl Chat {
|
||||
tasks.push(
|
||||
// Load all messages belonging to this room
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
match connect_relays.await {
|
||||
Ok(relays) => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.relays.update(cx, |this, cx| {
|
||||
*this = relays;
|
||||
cx.notify();
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Err(e) => {
|
||||
cx.update(|window, cx| {
|
||||
let result = load_messages.await;
|
||||
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
match result {
|
||||
Ok(events) => {
|
||||
this.insert_messages(events, cx);
|
||||
}
|
||||
Err(e) => {
|
||||
window.push_notification(e.to_string(), cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
})
|
||||
.ok();
|
||||
}),
|
||||
);
|
||||
|
||||
tasks.push(
|
||||
// Load all messages belonging to this room
|
||||
// Get messaging relays for all members
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
match load_messages.await {
|
||||
Ok(events) => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.insert_messages(events, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Err(e) => {
|
||||
cx.update(|window, cx| {
|
||||
window.push_notification(e.to_string(), cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
};
|
||||
let result = connect.await;
|
||||
|
||||
this.update_in(cx, |this, _window, cx| {
|
||||
match result {
|
||||
Ok(relays) => {
|
||||
this.relays.update(cx, |this, cx| {
|
||||
this.extend(relays);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
this.insert_warning(e.to_string(), cx);
|
||||
}
|
||||
};
|
||||
})
|
||||
.ok();
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -192,9 +191,12 @@ impl Chat {
|
||||
subscriptions.push(
|
||||
// Observe the messaging relays of the room's members
|
||||
cx.observe_in(&relays, window, |this, entity, _window, cx| {
|
||||
for (public_key, urls) in entity.read(cx).clone().into_iter() {
|
||||
let registry = Registry::global(cx);
|
||||
let relays = entity.read(cx).clone();
|
||||
|
||||
for (public_key, urls) in relays.iter() {
|
||||
if urls.is_empty() {
|
||||
let profile = Registry::read_global(cx).get_person(&public_key, cx);
|
||||
let profile = registry.read(cx).get_person(public_key, cx);
|
||||
let content = t!("chat.nip17_not_found", u = profile.name());
|
||||
|
||||
this.insert_warning(content, cx);
|
||||
@@ -206,7 +208,6 @@ impl Chat {
|
||||
subscriptions.push(
|
||||
// Observe when user close chat panel
|
||||
cx.on_release_in(window, move |this, window, cx| {
|
||||
this.disconnect_relays(cx);
|
||||
this.messages.clear();
|
||||
this.rendered_texts_by_id.clear();
|
||||
this.reports_by_id.clear();
|
||||
@@ -235,20 +236,6 @@ impl Chat {
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnect all relays when the user closes the chat panel
|
||||
fn disconnect_relays(&mut self, cx: &mut App) {
|
||||
let relays = self.relays.read(cx).clone();
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let client = nostr_client();
|
||||
|
||||
for relay in relays.values().flatten() {
|
||||
client.disconnect_relay(relay).await.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
/// Load all messages belonging to this room
|
||||
fn load_messages(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let load_messages = self.room.read(cx).load_messages(cx);
|
||||
@@ -273,11 +260,6 @@ impl Chat {
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn mention_popup(&mut self, _text: &str, _input: &Entity<InputState>, _cx: &mut Context<Self>) {
|
||||
// TODO: open mention popup at current cursor position
|
||||
}
|
||||
|
||||
/// Get user input content and merged all attachments
|
||||
fn input_content(&self, cx: &Context<Self>) -> String {
|
||||
let mut content = self.input.read(cx).value().trim().to_string();
|
||||
@@ -313,36 +295,48 @@ impl Chat {
|
||||
return;
|
||||
}
|
||||
|
||||
// Temporary disable the message input
|
||||
self.input.update(cx, |this, cx| {
|
||||
this.set_loading(false, cx);
|
||||
this.set_disabled(false, cx);
|
||||
this.set_value("", window, cx);
|
||||
});
|
||||
|
||||
// Get the backup setting
|
||||
let backup = AppSettings::get_backup_messages(cx);
|
||||
|
||||
// Get replies_to if it's present
|
||||
let replies = self.replies_to.read(cx).iter().copied().collect_vec();
|
||||
let replies: Vec<EventId> = self.replies_to.read(cx).iter().copied().collect();
|
||||
|
||||
// Get the current room entity
|
||||
let room = self.room.read(cx);
|
||||
let identity = Registry::read_global(cx).identity(cx).public_key();
|
||||
|
||||
// Create a temporary message for optimistic update
|
||||
let temp_message = room.create_temp_message(identity, &content, replies.as_ref());
|
||||
let temp_id = temp_message.id.unwrap();
|
||||
let rumor = room.create_message(&content, replies.as_ref(), cx);
|
||||
let rumor_id = rumor.id.unwrap();
|
||||
|
||||
// Create a task for sending the message in the background
|
||||
let send_message = room.send_in_background(&content, replies, backup, cx);
|
||||
let send_message = room.send_message(rumor.clone(), backup, cx);
|
||||
|
||||
// Optimistically update message list
|
||||
self.insert_message(Message::user(temp_message), true, cx);
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(100))
|
||||
.await;
|
||||
|
||||
// Remove all replies
|
||||
self.remove_all_replies(cx);
|
||||
|
||||
// remove all attachments
|
||||
self.remove_all_attachments(cx);
|
||||
|
||||
// Reset the input state
|
||||
self.input.update(cx, |this, cx| {
|
||||
this.set_value("", window, cx);
|
||||
});
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
this.insert_message(Message::user(rumor), true, cx);
|
||||
this.remove_all_replies(cx);
|
||||
this.remove_all_attachments(cx);
|
||||
this.input.update(cx, |this, cx| {
|
||||
this.set_loading(false, cx);
|
||||
this.set_disabled(false, cx);
|
||||
this.set_value("", window, cx);
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
|
||||
// Continue sending the message in the background
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
@@ -363,7 +357,7 @@ impl Chat {
|
||||
});
|
||||
|
||||
// Insert the sent reports
|
||||
this.reports_by_id.insert(temp_id, reports);
|
||||
this.reports_by_id.insert(rumor_id, reports);
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
@@ -377,37 +371,31 @@ impl Chat {
|
||||
.detach();
|
||||
}
|
||||
|
||||
/// Resend a failed message
|
||||
fn resend_message(&mut self, id: &EventId, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if let Some(reports) = self.reports_by_id.get(id).cloned() {
|
||||
if let Some(message) = self.message(id) {
|
||||
let backup = AppSettings::get_backup_messages(cx);
|
||||
let id_clone = id.to_owned();
|
||||
let message = message.content.to_owned();
|
||||
let task = self.room.read(cx).resend(reports, message, backup, cx);
|
||||
let id_clone = id.to_owned();
|
||||
let resend = self.room.read(cx).resend_message(reports, cx);
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
match task.await {
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let result = resend.await;
|
||||
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
match result {
|
||||
Ok(reports) => {
|
||||
if !reports.is_empty() {
|
||||
this.update(cx, |this, cx| {
|
||||
this.reports_by_id.entry(id_clone).and_modify(|this| {
|
||||
*this = reports;
|
||||
});
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
this.reports_by_id.entry(id_clone).and_modify(|this| {
|
||||
*this = reports;
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
Err(e) => {
|
||||
cx.update(|window, cx| {
|
||||
window.push_notification(e.to_string(), cx);
|
||||
})
|
||||
.ok();
|
||||
window.push_notification(Notification::error(e.to_string()), cx);
|
||||
}
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,7 +600,7 @@ impl Chat {
|
||||
});
|
||||
}
|
||||
|
||||
fn render_announcement(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
|
||||
fn render_announcement(&self, ix: usize, cx: &Context<Self>) -> AnyElement {
|
||||
v_flex()
|
||||
.id(ix)
|
||||
.group("")
|
||||
@@ -638,7 +626,7 @@ impl Chat {
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_warning(&mut self, ix: usize, content: String, cx: &mut Context<Self>) -> AnyElement {
|
||||
fn render_warning(&self, ix: usize, content: SharedString, cx: &Context<Self>) -> AnyElement {
|
||||
div()
|
||||
.id(ix)
|
||||
.relative()
|
||||
@@ -652,7 +640,7 @@ impl Chat {
|
||||
.text_sm()
|
||||
.text_color(cx.theme().warning_foreground)
|
||||
.child(Avatar::new("brand/system.png").size(rems(2.)))
|
||||
.child(SharedString::from(content)),
|
||||
.child(content),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
@@ -666,23 +654,6 @@ impl Chat {
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_message_not_found(&self, ix: usize, cx: &Context<Self>) -> AnyElement {
|
||||
div()
|
||||
.id(ix)
|
||||
.w_full()
|
||||
.py_1()
|
||||
.px_3()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().danger_foreground)
|
||||
.child(SharedString::from(ix.to_string()))
|
||||
.child(shared_t!("chat.not_found")),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_message(
|
||||
&self,
|
||||
ix: usize,
|
||||
@@ -1237,8 +1208,7 @@ impl Chat {
|
||||
weak_view.read_with(cx, |this, cx| this.new_subject(cx))
|
||||
{
|
||||
room.update(cx, |this, cx| {
|
||||
this.subject = Some(subject);
|
||||
cx.notify();
|
||||
this.set_subject(subject, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
@@ -1381,13 +1351,13 @@ impl Render for Chat {
|
||||
|
||||
this.render_message(ix, rendered, text, cx)
|
||||
}
|
||||
Message::Warning(content, _) => {
|
||||
this.render_warning(ix, content.to_owned(), cx)
|
||||
Message::Warning(content, _timestamp) => {
|
||||
this.render_warning(ix, SharedString::from(content), cx)
|
||||
}
|
||||
Message::System(_) => this.render_announcement(ix, cx),
|
||||
Message::System(_timestamp) => this.render_announcement(ix, cx),
|
||||
}
|
||||
} else {
|
||||
this.render_message_not_found(ix, cx)
|
||||
this.render_warning(ix, shared_t!("chat.not_found"), cx)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user