chore: improve ui responsiveness when send message

This commit is contained in:
2025-04-23 09:05:50 +07:00
parent 73b2eac080
commit 17251be3fd
2 changed files with 69 additions and 41 deletions

View File

@@ -1,13 +1,14 @@
use std::sync::Arc;
use account::Account;
use anyhow::{anyhow, Error};
use anyhow::Error;
use chrono::{Local, TimeZone};
use common::{compare, profile::SharedProfile, room_hash};
use global::get_client;
use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task, Window};
use itertools::Itertools;
use nostr_sdk::prelude::*;
use smol::channel::Receiver;
use crate::{
constants::{DAYS_IN_MONTH, HOURS_IN_DAY, MINUTES_IN_HOUR, NOW, SECONDS_IN_MINUTE},
@@ -20,6 +21,12 @@ pub struct IncomingEvent {
pub event: RoomMessage,
}
#[derive(Debug)]
pub enum SendStatus {
Sent(EventId),
Failed(Error),
}
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, Default)]
pub enum RoomKind {
Ongoing,
@@ -368,20 +375,17 @@ impl Room {
///
/// A Task that resolves to Result<Vec<String>, Error> where the
/// strings contain error messages for any failed sends
pub fn send_message(&self, content: String, cx: &App) -> Task<Result<Vec<String>, Error>> {
let account = Account::global(cx).read(cx);
let Some(profile) = account.profile.clone() else {
return Task::ready(Err(anyhow!("User is not logged in")));
};
pub fn send_message(&self, content: String, cx: &App) -> Option<Receiver<SendStatus>> {
let profile = Account::global(cx).read(cx).profile.clone()?;
let public_key = profile.public_key();
let subject = self.subject.clone();
let pubkeys = self.members.clone();
let (tx, rx) = smol::channel::bounded::<SendStatus>(pubkeys.len());
cx.background_spawn(async move {
let client = get_client();
let mut report = vec![];
let mut tags: Vec<Tag> = pubkeys
.iter()
@@ -401,16 +405,26 @@ impl Room {
}
for pubkey in pubkeys.iter() {
if let Err(e) = client
match client
.send_private_msg(*pubkey, &content, tags.clone())
.await
{
report.push(e.to_string());
Ok(output) => {
if let Err(e) = tx.send(SendStatus::Sent(output.val)).await {
log::error!("Failed to send message to {}: {}", pubkey, e);
}
}
Err(e) => {
if let Err(e) = tx.send(SendStatus::Failed(e.into())).await {
log::error!("Failed to send message to {}: {}", pubkey, e);
}
}
}
}
Ok(report)
})
.detach();
Some(rx)
}
/// Loads all messages for this room from the database

View File

@@ -1,6 +1,10 @@
use anyhow::{anyhow, Error};
use async_utility::task::spawn;
use chats::{message::RoomMessage, room::Room, ChatRegistry};
use chats::{
message::RoomMessage,
room::{Room, SendStatus},
ChatRegistry,
};
use common::{nip96_upload, profile::SharedProfile};
use global::{constants::IMAGE_SERVICE, get_client};
use gpui::{
@@ -221,11 +225,13 @@ impl Chat {
content = format!("{}\n{}", content, merged)
}
// Check if content is empty
if content.is_empty() {
window.push_notification("Cannot send an empty message", cx);
return;
}
// Update input state
self.input.update(cx, |this, cx| {
this.set_loading(true, window, cx);
this.set_disabled(true, window, cx);
@@ -234,35 +240,43 @@ impl Chat {
let room = self.room.read(cx);
let task = room.send_message(content, cx);
cx.spawn_in(window, async move |this, cx| match task.await {
Ok(reports) => {
cx.update(|window, cx| {
this.update(cx, |this, cx| {
this.input.update(cx, |this, cx| {
this.set_loading(false, window, cx);
this.set_disabled(false, window, cx);
this.set_text("", window, cx);
});
cx.spawn_in(window, async move |this, cx| {
let mut received = false;
match task {
Some(rx) => {
while let Ok(message) = rx.recv().await {
if let SendStatus::Failed(error) = message {
cx.update(|window, cx| {
window.push_notification(
Notification::error(error.to_string())
.title("Message Failed to Send"),
cx,
);
})
.ok();
} else if !received {
cx.update(|window, cx| {
this.update(cx, |this, cx| {
this.input.update(cx, |this, cx| {
this.set_loading(false, window, cx);
this.set_disabled(false, window, cx);
this.set_text("", window, cx);
});
received = true;
})
.ok();
})
.ok();
}
}
}
None => {
cx.update(|window, cx| {
window.push_notification(Notification::error("User is not logged in"), cx);
})
.ok();
for item in reports.into_iter() {
window.push_notification(
Notification::error(item).title("Message Failed to Send"),
cx,
);
}
})
.ok();
}
Err(e) => {
cx.update(|window, cx| {
window.push_notification(
Notification::error(e.to_string()).title("Message Failed to Send"),
cx,
);
})
.ok();
}
}
})
.detach();