wip
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m25s
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m25s
This commit is contained in:
@@ -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);
|
||||
})),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user