.
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 5m17s

This commit is contained in:
2026-02-19 10:10:16 +07:00
parent 3e8efdd0ef
commit fad30a89f1
17 changed files with 226 additions and 149 deletions

View File

@@ -30,6 +30,7 @@ use ui::indicator::Indicator;
use ui::input::{InputEvent, InputState, TextInput};
use ui::menu::{ContextMenuExt, DropdownMenu};
use ui::notification::Notification;
use ui::scroll::Scrollbar;
use ui::{
h_flex, v_flex, Disableable, Icon, IconName, InteractiveElementExt, Sizable, StyledExt,
WindowExtension,
@@ -62,11 +63,14 @@ pub struct ChatPanel {
rendered_texts_by_id: BTreeMap<EventId, RenderedText>,
/// Mapping message (rumor event) ids to their reports
reports_by_id: Arc<RwLock<BTreeMap<EventId, Vec<SendReport>>>>,
reports_by_id: Entity<BTreeMap<EventId, Vec<SendReport>>>,
/// Input state
input: Entity<InputState>,
/// Sent message ids
sent_ids: Arc<RwLock<Vec<EventId>>>,
/// Replies to
replies_to: Entity<HashSet<EventId>>,
@@ -88,6 +92,7 @@ impl ChatPanel {
// Define attachments and replies_to entities
let attachments = cx.new(|_| vec![]);
let replies_to = cx.new(|_| HashSet::new());
let reports_by_id = cx.new(|_| BTreeMap::new());
// Define list of messages
let messages = BTreeSet::from([Message::system()]);
@@ -140,7 +145,8 @@ impl ChatPanel {
replies_to,
attachments,
rendered_texts_by_id: BTreeMap::new(),
reports_by_id: Arc::new(RwLock::new(BTreeMap::new())),
reports_by_id,
sent_ids: Arc::new(RwLock::new(Vec::new())),
uploading: false,
subscriptions,
tasks: vec![],
@@ -151,7 +157,9 @@ impl ChatPanel {
fn handle_notifications(&mut self, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
let reports = self.reports_by_id.clone();
let sent_ids = self.sent_ids.clone();
let (tx, rx) = flume::bounded::<(EventId, RelayUrl)>(256);
self.tasks.push(cx.background_spawn(async move {
let mut notifications = client.notifications();
@@ -162,18 +170,33 @@ impl ChatPanel {
relay_url,
} = notification
{
let mut writer = reports.write().await;
let sent_ids = sent_ids.read().await;
for reports in writer.values_mut() {
for report in reports.iter_mut() {
if let Some(output) = report.output.as_mut() {
if output.id() == &event_id {
output.success.insert(relay_url.clone());
if sent_ids.contains(&event_id) {
tx.send_async((event_id, relay_url)).await.ok();
}
}
}
Ok(())
}));
self.tasks.push(cx.spawn(async move |this, cx| {
while let Ok((event_id, relay_url)) = rx.recv_async().await {
this.update(cx, |this, cx| {
this.reports_by_id.update(cx, |this, cx| {
for reports in this.values_mut() {
for report in reports.iter_mut() {
if let Some(output) = report.output.as_mut() {
if output.id() == &event_id {
output.success.insert(relay_url.clone());
cx.notify();
}
}
}
}
}
}
});
})?;
}
Ok(())
@@ -301,6 +324,7 @@ impl ChatPanel {
/// Send message in the background and wait for the response
fn send_and_wait(&mut self, rumor: UnsignedEvent, window: &mut Window, cx: &mut Context<Self>) {
let sent_ids = self.sent_ids.clone();
// This can't fail, because we already ensured that the ID is set
let id = rumor.id.unwrap();
@@ -316,6 +340,10 @@ impl ChatPanel {
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
let outputs = task.await;
// Add sent IDs to the list
let mut sent_ids = sent_ids.write().await;
sent_ids.extend(outputs.iter().filter_map(|output| output.gift_wrap_id));
// Update the state
this.update(cx, |this, cx| {
this.insert_reports(id, outputs, cx);
@@ -342,10 +370,12 @@ impl ChatPanel {
})
}
/// Synchronously insert reports
/// Insert reports
fn insert_reports(&mut self, id: EventId, reports: Vec<SendReport>, cx: &mut Context<Self>) {
self.reports_by_id.write_blocking().insert(id, reports);
cx.notify();
self.reports_by_id.update(cx, |this, cx| {
this.insert(id, reports);
cx.notify();
});
}
/// Insert a message into the chat panel
@@ -379,32 +409,32 @@ impl ChatPanel {
}
/// Check if a message is pending
fn sent_pending(&self, id: &EventId) -> bool {
fn sent_pending(&self, id: &EventId, cx: &App) -> bool {
self.reports_by_id
.read_blocking()
.read(cx)
.get(id)
.is_some_and(|reports| reports.iter().any(|r| r.pending()))
}
/// Check if a message was sent successfully by its ID
fn sent_success(&self, id: &EventId) -> bool {
fn sent_success(&self, id: &EventId, cx: &App) -> bool {
self.reports_by_id
.read_blocking()
.read(cx)
.get(id)
.is_some_and(|reports| reports.iter().any(|r| r.success()))
}
/// Check if a message failed to send by its ID
fn sent_failed(&self, id: &EventId) -> bool {
fn sent_failed(&self, id: &EventId, cx: &App) -> Option<bool> {
self.reports_by_id
.read_blocking()
.read(cx)
.get(id)
.is_some_and(|reports| reports.iter().all(|r| !r.success()))
.map(|reports| reports.iter().all(|r| !r.success()))
}
/// Get all sent reports for a message by its ID
fn sent_reports(&self, id: &EventId) -> Option<Vec<SendReport>> {
self.reports_by_id.read_blocking().get(id).cloned()
fn sent_reports(&self, id: &EventId, cx: &App) -> Option<Vec<SendReport>> {
self.reports_by_id.read(cx).get(id).cloned()
}
/// Get a message by its ID
@@ -624,13 +654,13 @@ impl ChatPanel {
let has_replies = !replies.is_empty();
// Check if message is sent failed
let sent_pending = self.sent_pending(&id);
let sent_pending = self.sent_pending(&id, cx);
// Check if message is sent successfully
let sent_success = self.sent_success(&id);
let sent_success = self.sent_success(&id, cx);
// Check if message is sent failed
let sent_failed = self.sent_failed(&id);
let sent_failed = self.sent_failed(&id, cx);
// Hide avatar setting
let hide_avatar = AppSettings::get_hide_avatar(cx);
@@ -689,8 +719,10 @@ impl ChatPanel {
this.children(self.render_message_replies(replies, cx))
})
.child(rendered_text)
.when(sent_failed, |this| {
this.child(deferred(self.render_message_reports(&id, cx)))
.when_some(sent_failed, |this, failed| {
this.when(failed, |this| {
this.child(deferred(self.render_message_reports(&id, cx)))
})
}),
),
)
@@ -755,11 +787,11 @@ impl ChatPanel {
items
}
fn render_sent_indicator(&self, id: &EventId, _cx: &Context<Self>) -> impl IntoElement {
fn render_sent_indicator(&self, id: &EventId, cx: &Context<Self>) -> impl IntoElement {
div()
.id(SharedString::from(id.to_hex()))
.child(SharedString::from("• Sent"))
.when_some(self.sent_reports(id), |this, reports| {
.when_some(self.sent_reports(id, cx), |this, reports| {
this.on_click(move |_e, window, cx| {
let reports = reports.clone();
@@ -791,7 +823,7 @@ impl ChatPanel {
.child(SharedString::from(
"Failed to send message. Click to see details.",
))
.when_some(self.sent_reports(id), |this, reports| {
.when_some(self.sent_reports(id, cx), |this, reports| {
this.on_click(move |_e, window, cx| {
let reports = reports.clone();
@@ -1155,15 +1187,19 @@ impl Render for ChatPanel {
.on_action(cx.listener(Self::on_command))
.size_full()
.child(
list(
self.list_state.clone(),
cx.processor(|this, ix, window, cx| {
// Get and render message by index
this.render_message(ix, window, cx)
}),
)
.flex_1()
.size_full(),
div()
.flex_1()
.size_full()
.child(
list(
self.list_state.clone(),
cx.processor(move |this, ix, window, cx| {
this.render_message(ix, window, cx)
}),
)
.size_full(),
)
.child(Scrollbar::vertical(&self.list_state)),
)
.child(
v_flex()
@@ -1206,7 +1242,7 @@ impl Render for ChatPanel {
.dropdown_menu_with_anchor(
gpui::Corner::BottomLeft,
move |this, _window, _cx| {
this//.axis(gpui::Axis::Horizontal)
this.horizontal()
.menu("👍", Box::new(Command::Insert("👍")))
.menu("👎", Box::new(Command::Insert("👎")))
.menu("😄", Box::new(Command::Insert("😄")))