chore: improve ui responsiveness when send message
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use account::Account;
|
use account::Account;
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::Error;
|
||||||
use chrono::{Local, TimeZone};
|
use chrono::{Local, TimeZone};
|
||||||
use common::{compare, profile::SharedProfile, room_hash};
|
use common::{compare, profile::SharedProfile, room_hash};
|
||||||
use global::get_client;
|
use global::get_client;
|
||||||
use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task, Window};
|
use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task, Window};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
|
use smol::channel::Receiver;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{DAYS_IN_MONTH, HOURS_IN_DAY, MINUTES_IN_HOUR, NOW, SECONDS_IN_MINUTE},
|
constants::{DAYS_IN_MONTH, HOURS_IN_DAY, MINUTES_IN_HOUR, NOW, SECONDS_IN_MINUTE},
|
||||||
@@ -20,6 +21,12 @@ pub struct IncomingEvent {
|
|||||||
pub event: RoomMessage,
|
pub event: RoomMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SendStatus {
|
||||||
|
Sent(EventId),
|
||||||
|
Failed(Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, Default)]
|
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, Default)]
|
||||||
pub enum RoomKind {
|
pub enum RoomKind {
|
||||||
Ongoing,
|
Ongoing,
|
||||||
@@ -368,20 +375,17 @@ impl Room {
|
|||||||
///
|
///
|
||||||
/// A Task that resolves to Result<Vec<String>, Error> where the
|
/// A Task that resolves to Result<Vec<String>, Error> where the
|
||||||
/// strings contain error messages for any failed sends
|
/// strings contain error messages for any failed sends
|
||||||
pub fn send_message(&self, content: String, cx: &App) -> Task<Result<Vec<String>, Error>> {
|
pub fn send_message(&self, content: String, cx: &App) -> Option<Receiver<SendStatus>> {
|
||||||
let account = Account::global(cx).read(cx);
|
let profile = Account::global(cx).read(cx).profile.clone()?;
|
||||||
|
|
||||||
let Some(profile) = account.profile.clone() else {
|
|
||||||
return Task::ready(Err(anyhow!("User is not logged in")));
|
|
||||||
};
|
|
||||||
|
|
||||||
let public_key = profile.public_key();
|
let public_key = profile.public_key();
|
||||||
|
|
||||||
let subject = self.subject.clone();
|
let subject = self.subject.clone();
|
||||||
let pubkeys = self.members.clone();
|
let pubkeys = self.members.clone();
|
||||||
|
|
||||||
|
let (tx, rx) = smol::channel::bounded::<SendStatus>(pubkeys.len());
|
||||||
|
|
||||||
cx.background_spawn(async move {
|
cx.background_spawn(async move {
|
||||||
let client = get_client();
|
let client = get_client();
|
||||||
let mut report = vec![];
|
|
||||||
|
|
||||||
let mut tags: Vec<Tag> = pubkeys
|
let mut tags: Vec<Tag> = pubkeys
|
||||||
.iter()
|
.iter()
|
||||||
@@ -401,16 +405,26 @@ impl Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for pubkey in pubkeys.iter() {
|
for pubkey in pubkeys.iter() {
|
||||||
if let Err(e) = client
|
match client
|
||||||
.send_private_msg(*pubkey, &content, tags.clone())
|
.send_private_msg(*pubkey, &content, tags.clone())
|
||||||
.await
|
.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
|
/// Loads all messages for this room from the database
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use async_utility::task::spawn;
|
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 common::{nip96_upload, profile::SharedProfile};
|
||||||
use global::{constants::IMAGE_SERVICE, get_client};
|
use global::{constants::IMAGE_SERVICE, get_client};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
@@ -221,11 +225,13 @@ impl Chat {
|
|||||||
content = format!("{}\n{}", content, merged)
|
content = format!("{}\n{}", content, merged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if content is empty
|
||||||
if content.is_empty() {
|
if content.is_empty() {
|
||||||
window.push_notification("Cannot send an empty message", cx);
|
window.push_notification("Cannot send an empty message", cx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update input state
|
||||||
self.input.update(cx, |this, cx| {
|
self.input.update(cx, |this, cx| {
|
||||||
this.set_loading(true, window, cx);
|
this.set_loading(true, window, cx);
|
||||||
this.set_disabled(true, window, cx);
|
this.set_disabled(true, window, cx);
|
||||||
@@ -234,8 +240,22 @@ impl Chat {
|
|||||||
let room = self.room.read(cx);
|
let room = self.room.read(cx);
|
||||||
let task = room.send_message(content, cx);
|
let task = room.send_message(content, cx);
|
||||||
|
|
||||||
cx.spawn_in(window, async move |this, cx| match task.await {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
Ok(reports) => {
|
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| {
|
cx.update(|window, cx| {
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.input.update(cx, |this, cx| {
|
this.input.update(cx, |this, cx| {
|
||||||
@@ -243,27 +263,21 @@ impl Chat {
|
|||||||
this.set_disabled(false, window, cx);
|
this.set_disabled(false, window, cx);
|
||||||
this.set_text("", window, cx);
|
this.set_text("", window, cx);
|
||||||
});
|
});
|
||||||
|
received = true;
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
for item in reports.into_iter() {
|
|
||||||
window.push_notification(
|
|
||||||
Notification::error(item).title("Message Failed to Send"),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
Err(e) => {
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
cx.update(|window, cx| {
|
cx.update(|window, cx| {
|
||||||
window.push_notification(
|
window.push_notification(Notification::error("User is not logged in"), cx);
|
||||||
Notification::error(e.to_string()).title("Message Failed to Send"),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user