@@ -63,6 +63,7 @@ pub struct ChatPanel {
focus_handle: FocusHandle,
open_context_menu: Option<(u64, Subscription)>,
highlighted_message: Option<(u64, Task<()>)>,
+ last_acknowledged_message_id: Option<u64>,
}
#[derive(Serialize, Deserialize)]
@@ -126,6 +127,7 @@ impl ChatPanel {
focus_handle: cx.focus_handle(),
open_context_menu: None,
highlighted_message: None,
+ last_acknowledged_message_id: None,
};
if let Some(channel_id) = ActiveCall::global(cx)
@@ -281,6 +283,13 @@ impl ChatPanel {
fn acknowledge_last_message(&mut self, cx: &mut ViewContext<Self>) {
if self.active && self.is_scrolled_to_bottom {
if let Some((chat, _)) = &self.active_chat {
+ if let Some(channel_id) = self.channel_id(cx) {
+ self.last_acknowledged_message_id = self
+ .channel_store
+ .read(cx)
+ .last_acknowledge_message_id(channel_id);
+ }
+
chat.update(cx, |chat, cx| {
chat.acknowledge_last_message(cx);
});
@@ -454,120 +463,145 @@ impl ChatPanel {
cx.theme().colors().panel_background
};
- v_flex().w_full().relative().child(
- div()
- .bg(background)
- .rounded_md()
- .overflow_hidden()
- .px_1()
- .py_0p5()
- .when(!is_continuation_from_previous, |this| {
- this.mt_2().child(
- h_flex()
- .text_ui_sm()
- .child(div().absolute().child(
- Avatar::new(message.sender.avatar_uri.clone()).size(rems(1.)),
- ))
- .child(
+ v_flex()
+ .w_full()
+ .relative()
+ .child(
+ div()
+ .bg(background)
+ .rounded_md()
+ .overflow_hidden()
+ .px_1()
+ .py_0p5()
+ .when(!is_continuation_from_previous, |this| {
+ this.mt_2().child(
+ h_flex()
+ .text_ui_sm()
+ .child(div().absolute().child(
+ Avatar::new(message.sender.avatar_uri.clone()).size(rems(1.)),
+ ))
+ .child(
+ div()
+ .pl(cx.rem_size() + px(6.0))
+ .pr(px(8.0))
+ .font_weight(FontWeight::BOLD)
+ .child(Label::new(message.sender.github_login.clone())),
+ )
+ .child(
+ Label::new(format_timestamp(
+ OffsetDateTime::now_utc(),
+ message.timestamp,
+ self.local_timezone,
+ None,
+ ))
+ .size(LabelSize::Small)
+ .color(Color::Muted),
+ ),
+ )
+ })
+ .when(
+ message.reply_to_message_id.is_some() && reply_to_message.is_none(),
+ |this| {
+ const MESSAGE_DELETED: &str = "Message has been deleted";
+
+ let body_text = StyledText::new(MESSAGE_DELETED).with_highlights(
+ &cx.text_style(),
+ vec![(
+ 0..MESSAGE_DELETED.len(),
+ HighlightStyle {
+ font_style: Some(FontStyle::Italic),
+ ..Default::default()
+ },
+ )],
+ );
+
+ this.child(
div()
- .pl(cx.rem_size() + px(6.0))
- .pr(px(8.0))
- .font_weight(FontWeight::BOLD)
- .child(Label::new(message.sender.github_login.clone())),
+ .border_l_2()
+ .text_ui_xs()
+ .border_color(cx.theme().colors().border)
+ .px_1()
+ .py_0p5()
+ .child(body_text),
)
- .child(
- Label::new(format_timestamp(
- OffsetDateTime::now_utc(),
- message.timestamp,
- self.local_timezone,
- None,
- ))
- .size(LabelSize::Small)
- .color(Color::Muted),
- ),
+ },
)
- })
- .when(
- message.reply_to_message_id.is_some() && reply_to_message.is_none(),
- |this| {
- const MESSAGE_DELETED: &str = "Message has been deleted";
-
- let body_text = StyledText::new(MESSAGE_DELETED).with_highlights(
- &cx.text_style(),
- vec![(
- 0..MESSAGE_DELETED.len(),
- HighlightStyle {
- font_style: Some(FontStyle::Italic),
- ..Default::default()
- },
- )],
- );
-
- this.child(
- div()
- .border_l_2()
- .text_ui_xs()
- .border_color(cx.theme().colors().border)
- .px_1()
- .py_0p5()
- .child(body_text),
- )
- },
- )
- .when_some(reply_to_message, |el, reply_to_message| {
- el.child(self.render_replied_to_message(
- Some(message.id),
- &reply_to_message,
- cx,
- ))
- })
- .when(mentioning_you || replied_to_you, |this| this.my_0p5())
- .map(|el| {
- let text = self.markdown_data.entry(message.id).or_insert_with(|| {
- Self::render_markdown_with_mentions(
- &self.languages,
- self.client.id(),
- &message,
+ .when_some(reply_to_message, |el, reply_to_message| {
+ el.child(self.render_replied_to_message(
+ Some(message.id),
+ &reply_to_message,
+ cx,
+ ))
+ })
+ .when(mentioning_you || replied_to_you, |this| this.my_0p5())
+ .map(|el| {
+ let text = self.markdown_data.entry(message.id).or_insert_with(|| {
+ Self::render_markdown_with_mentions(
+ &self.languages,
+ self.client.id(),
+ &message,
+ )
+ });
+ el.child(
+ v_flex()
+ .w_full()
+ .text_ui_sm()
+ .id(element_id)
+ .group("")
+ .child(text.element("body".into(), cx))
+ .child(
+ div()
+ .absolute()
+ .z_index(1)
+ .right_0()
+ .w_6()
+ .bg(background)
+ .when(!self.has_open_menu(message_id), |el| {
+ el.visible_on_hover("")
+ })
+ .when_some(message_id, |el, message_id| {
+ el.child(
+ popover_menu(("menu", message_id))
+ .trigger(IconButton::new(
+ ("trigger", message_id),
+ IconName::Ellipsis,
+ ))
+ .menu(move |cx| {
+ Some(Self::render_message_menu(
+ &this,
+ message_id,
+ can_delete_message,
+ cx,
+ ))
+ }),
+ )
+ }),
+ ),
)
- });
- el.child(
- v_flex()
- .w_full()
- .text_ui_sm()
- .id(element_id)
- .group("")
- .child(text.element("body".into(), cx))
+ }),
+ )
+ .when(
+ self.last_acknowledged_message_id
+ .is_some_and(|l| Some(l) == message_id),
+ |this| {
+ this.child(
+ h_flex()
+ .py_2()
+ .gap_1()
+ .items_center()
+ .child(div().w_full().h_0p5().bg(cx.theme().colors().border))
.child(
div()
- .absolute()
- .z_index(1)
- .right_0()
- .w_6()
- .bg(background)
- .when(!self.has_open_menu(message_id), |el| {
- el.visible_on_hover("")
- })
- .when_some(message_id, |el, message_id| {
- el.child(
- popover_menu(("menu", message_id))
- .trigger(IconButton::new(
- ("trigger", message_id),
- IconName::Ellipsis,
- ))
- .menu(move |cx| {
- Some(Self::render_message_menu(
- &this,
- message_id,
- can_delete_message,
- cx,
- ))
- }),
- )
- }),
- ),
+ .px_1()
+ .rounded_md()
+ .text_ui_xs()
+ .bg(cx.theme().colors().background)
+ .child("New messages"),
+ )
+ .child(div().w_full().h_0p5().bg(cx.theme().colors().border)),
)
- }),
- )
+ },
+ )
}
fn has_open_menu(&self, message_id: Option<u64>) -> bool {
@@ -682,8 +716,11 @@ impl ChatPanel {
cx.spawn(|this, mut cx| async move {
let chat = open_chat.await?;
- this.update(&mut cx, |this, cx| {
+ let highlight_message_id = scroll_to_message_id;
+ let scroll_to_message_id = this.update(&mut cx, |this, cx| {
this.set_active_chat(chat.clone(), cx);
+
+ scroll_to_message_id.or_else(|| this.last_acknowledged_message_id)
})?;
if let Some(message_id) = scroll_to_message_id {
@@ -691,21 +728,22 @@ impl ChatPanel {
ChannelChat::load_history_since_message(chat.clone(), message_id, (*cx).clone())
.await
{
- let task = cx.spawn({
- let this = this.clone();
-
- |mut cx| async move {
- cx.background_executor().timer(Duration::from_secs(2)).await;
- this.update(&mut cx, |this, cx| {
- this.highlighted_message.take();
- cx.notify();
- })
- .ok();
+ this.update(&mut cx, |this, cx| {
+ if let Some(highlight_message_id) = highlight_message_id {
+ let task = cx.spawn({
+ |this, mut cx| async move {
+ cx.background_executor().timer(Duration::from_secs(2)).await;
+ this.update(&mut cx, |this, cx| {
+ this.highlighted_message.take();
+ cx.notify();
+ })
+ .ok();
+ }
+ });
+
+ this.highlighted_message = Some((highlight_message_id, task));
}
- });
- this.update(&mut cx, |this, cx| {
- this.highlighted_message = Some((message_id, task));
if this.active_chat.as_ref().map_or(false, |(c, _)| *c == chat) {
this.message_list.scroll_to(ListOffset {
item_ix,