wip
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m25s

This commit is contained in:
2026-02-15 16:52:35 +07:00
parent a1aaa30a48
commit 452253bece
13 changed files with 610 additions and 569 deletions

View File

@@ -10,8 +10,8 @@ use gpui::{
div, img, list, px, red, relative, rems, svg, white, AnyElement, App, AppContext,
ClipboardItem, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
IntoElement, ListAlignment, ListOffset, ListState, MouseButton, ObjectFit, ParentElement,
PathPromptOptions, Render, RetainAllImageCache, SharedString, StatefulInteractiveElement,
Styled, StyledImage, Subscription, Task, WeakEntity, Window,
PathPromptOptions, Render, SharedString, StatefulInteractiveElement, Styled, StyledImage,
Subscription, Task, WeakEntity, Window,
};
use gpui_tokio::Tokio;
use indexset::{BTreeMap, BTreeSet};
@@ -47,7 +47,6 @@ pub fn init(room: WeakEntity<Room>, window: &mut Window, cx: &mut App) -> Entity
pub struct ChatPanel {
id: SharedString,
focus_handle: FocusHandle,
image_cache: Entity<RetainAllImageCache>,
/// Chat Room
room: WeakEntity<Room>,
@@ -77,14 +76,22 @@ pub struct ChatPanel {
uploading: bool,
/// Async operations
tasks: SmallVec<[Task<()>; 2]>,
tasks: SmallVec<[Task<Result<(), Error>>; 2]>,
/// Event subscriptions
_subscriptions: SmallVec<[Subscription; 2]>,
subscriptions: SmallVec<[Subscription; 2]>,
}
impl ChatPanel {
pub fn new(room: WeakEntity<Room>, window: &mut Window, cx: &mut Context<Self>) -> Self {
// Define attachments and replies_to entities
let attachments = cx.new(|_| vec![]);
let replies_to = cx.new(|_| HashSet::new());
// Define list of messages
let messages = BTreeSet::from([Message::system()]);
let list_state = ListState::new(messages.len(), ListAlignment::Bottom, px(1024.));
// Get room id and name
let (id, name) = room
.read_with(cx, |this, _cx| {
@@ -104,74 +111,24 @@ impl ChatPanel {
.clean_on_escape()
});
// Define attachments and replies_to entities
let attachments = cx.new(|_| vec![]);
let replies_to = cx.new(|_| HashSet::new());
// Define list of messages
let messages = BTreeSet::from([Message::system()]);
let list_state = ListState::new(messages.len(), ListAlignment::Bottom, px(1024.));
let mut subscriptions = smallvec![];
let mut tasks = smallvec![];
if let Some(room) = room.upgrade() {
let connect = room.read(cx).connect(cx);
let get_messages = room.read(cx).get_messages(cx);
tasks.push(
// Get messaging relays and encryption keys announcement for each member
cx.background_spawn(async move {
if let Err(e) = connect.await {
log::error!("Failed to initialize room: {}", e);
}
}),
);
tasks.push(
// Load all messages belonging to this room
cx.spawn_in(window, async move |this, cx| {
let result = get_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();
}),
);
subscriptions.push(
// Subscribe to room events
cx.subscribe_in(&room, window, move |this, _room, event, window, cx| {
match event {
RoomEvent::Incoming(message) => {
this.insert_message(message, false, cx);
}
RoomEvent::Reload => {
this.load_messages(window, cx);
}
// Define subscriptions
let subscriptions =
smallvec![
cx.subscribe_in(&input, window, move |this, _input, event, window, cx| {
if let InputEvent::PressEnter { .. } = event {
this.send_text_message(window, cx);
};
}),
);
}
})
];
subscriptions.push(
// Subscribe to input events
cx.subscribe_in(&input, window, move |this, _input, event, window, cx| {
if let InputEvent::PressEnter { .. } = event {
this.send_input_message(window, cx);
};
}),
);
// Define all functions that will run after the current cycle
cx.defer_in(window, |this, window, cx| {
this.subscribe_room_events(window, cx);
this.get_messages(window, cx);
});
Self {
focus_handle: cx.focus_handle(),
id,
messages,
room,
@@ -182,32 +139,47 @@ impl ChatPanel {
rendered_texts_by_id: BTreeMap::new(),
reports_by_id: BTreeMap::new(),
uploading: false,
image_cache: RetainAllImageCache::new(cx),
focus_handle: cx.focus_handle(),
_subscriptions: subscriptions,
tasks,
subscriptions,
tasks: smallvec![],
}
}
/// Load all messages belonging to this room
fn load_messages(&mut self, window: &mut Window, cx: &mut Context<Self>) {
if let Ok(get_messages) = self.room.read_with(cx, |this, cx| this.get_messages(cx)) {
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
let result = get_messages.await;
fn subscribe_room_events(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Some(room) = self.room.upgrade() else {
return;
};
this.update_in(cx, |this, window, cx| {
match result {
Ok(events) => {
this.insert_messages(&events, cx);
}
Err(e) => {
window.push_notification(Notification::error(e.to_string()), cx);
}
};
})
.ok();
}));
}
self.subscriptions.push(
// Subscribe to room events
cx.subscribe_in(&room, window, move |this, _room, event, window, cx| {
match event {
RoomEvent::Incoming(message) => {
this.insert_message(message, false, cx);
}
RoomEvent::Reload => {
this.get_messages(window, cx);
}
};
}),
);
}
/// Load all messages belonging to this room
fn get_messages(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
let Ok(get_messages) = self.room.read_with(cx, |this, cx| this.get_messages(cx)) else {
return;
};
self.tasks.push(cx.spawn(async move |this, cx| {
let events = get_messages.await?;
// Update message list
this.update(cx, |this, cx| {
this.insert_messages(&events, cx);
})?;
Ok(())
}));
}
/// Get user input content and merged all attachments
@@ -235,7 +207,7 @@ impl ChatPanel {
content
}
fn send_input_message(&mut self, window: &mut Window, cx: &mut Context<Self>) {
fn send_text_message(&mut self, window: &mut Window, cx: &mut Context<Self>) {
// Get the message which includes all attachments
let content = self.get_input_value(cx);
@@ -250,80 +222,12 @@ impl ChatPanel {
/// Send a message to all members of the chat
fn send_message(&mut self, value: &str, window: &mut Window, cx: &mut Context<Self>) {
// Get replies_to if it's present
let replies: Vec<EventId> = self.replies_to.read(cx).iter().copied().collect();
// TODO
}
// Get a task to create temporary message for optimistic update
let Ok(get_rumor) = self
.room
.read_with(cx, |this, cx| this.create_message(value, replies, cx))
else {
return;
};
// Optimistically update message list
let task: Task<Result<(), Error>> = cx.spawn_in(window, async move |this, cx| {
let mut rumor = get_rumor.await?;
let rumor_id = rumor.id();
// Update the message list and reset the states
this.update_in(cx, |this, window, cx| {
this.remove_all_replies(cx);
this.remove_all_attachments(cx);
// Reset the input to its default state
this.input.update(cx, |this, cx| {
this.set_loading(false, cx);
this.set_disabled(false, cx);
this.set_value("", window, cx);
});
// Update the message list
this.insert_message(&rumor, true, cx);
if let Ok(task) = this
.room
.read_with(cx, |this, cx| this.send_message(&rumor, cx))
{
this.tasks.push(cx.spawn_in(window, async move |this, cx| {
let result = task.await;
this.update_in(cx, |this, window, cx| {
match result {
Ok(reports) => {
// Update room's status
this.room
.update(cx, |this, cx| {
if this.kind != RoomKind::Ongoing {
// Update the room kind to ongoing,
// but keep the room kind if send failed
if reports.iter().all(|r| !r.is_sent_success()) {
this.kind = RoomKind::Ongoing;
cx.notify();
}
}
})
.ok();
// Insert the sent reports
this.reports_by_id.insert(rumor_id, reports);
cx.notify();
}
Err(e) => {
window.push_notification(e.to_string(), cx);
}
}
})
.ok();
}))
}
})?;
Ok(())
});
task.detach();
fn insert_reports(&mut self, id: EventId, reports: Vec<SendReport>, cx: &mut Context<Self>) {
self.reports_by_id.insert(id, reports);
cx.notify();
}
/// Insert a message into the chat panel
@@ -749,7 +653,8 @@ impl ChatPanel {
let mut items = Vec::with_capacity(reports.len());
for report in reports.iter() {
items.push(Self::render_report(report, cx))
//items.push(Self::render_report(report, cx))
items.push(div())
}
items
@@ -781,7 +686,8 @@ impl ChatPanel {
let mut items = Vec::with_capacity(reports.len());
for report in reports.iter() {
items.push(Self::render_report(report, cx))
//items.push(Self::render_report(report, cx))
items.push(div())
}
items
@@ -791,6 +697,7 @@ impl ChatPanel {
})
}
/*
fn render_report(report: &SendReport, cx: &App) -> impl IntoElement {
let persons = PersonRegistry::global(cx);
let profile = persons.read(cx).get(&report.receiver, cx);
@@ -940,6 +847,7 @@ impl ChatPanel {
)
})
}
*/
fn render_border(&self, cx: &Context<Self>) -> impl IntoElement {
div()
@@ -1174,7 +1082,6 @@ impl Render for ChatPanel {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.on_action(cx.listener(Self::on_command))
.image_cache(self.image_cache.clone())
.size_full()
.child(
list(
@@ -1246,7 +1153,7 @@ impl Render for ChatPanel {
.ghost()
.large()
.on_click(cx.listener(move |this, _ev, window, cx| {
this.send_input_message(window, cx);
this.send_text_message(window, cx);
})),
),
),