Compare commits

...

6 Commits

Author SHA1 Message Date
Mikayla
cc4fb1c1b5 zed 0.107.1 2023-10-04 15:44:17 -07:00
Mikayla Maki
fc3d754aea Remove old code from notes icon click handler (#3085)
Release Notes:

- Fix clicking the notes icon when people are in the channel (preview
only)
2023-10-04 15:43:24 -07:00
Mikayla Maki
643f3db2b2 107 channel touch ups (#3087)
Release Notes:

- Add user avatars to channel chat messages
- Group messages by sender
- Fix visual bugs in new chat and note buttons
2023-10-04 15:43:16 -07:00
Max Brunsfeld
b90c04009f Ensure chat messages are retrieved in order of id (#3086)
Also, remove logic for implicitly marking chat messages as observed when
they are fetched. I think this is unnecessary, because the client always
explicitly acknowledges messages when they are shown.

Release Notes:

- Fixed a bug where chat messages were shown out of order (preview only)
2023-10-04 15:43:08 -07:00
Conrad Irwin
11f7a2cb0e Fix panic in increment (#3084)
Release Notes:

- Fixes a panic in vim when incrementing a non-number.
2023-10-04 15:40:30 -06:00
Joseph T. Lyons
8bdc59703a v0.107.x preview 2023-10-04 15:00:34 -04:00
12 changed files with 172 additions and 121 deletions

2
Cargo.lock generated
View File

@@ -10063,7 +10063,7 @@ dependencies = [
[[package]]
name = "zed"
version = "0.107.0"
version = "0.107.1"
dependencies = [
"activity_indicator",
"anyhow",

View File

@@ -9,13 +9,3 @@ pub mod projects;
pub mod rooms;
pub mod servers;
pub mod users;
fn max_assign<T: Ord>(max: &mut Option<T>, val: T) {
if let Some(max_val) = max {
if val > *max_val {
*max = Some(val);
}
} else {
*max = Some(val);
}
}

View File

@@ -89,17 +89,14 @@ impl Database {
let mut rows = channel_message::Entity::find()
.filter(condition)
.order_by_asc(channel_message::Column::Id)
.limit(count as u64)
.stream(&*tx)
.await?;
let mut max_id = None;
let mut messages = Vec::new();
while let Some(row) = rows.next().await {
let row = row?;
max_assign(&mut max_id, row.id);
let nonce = row.nonce.as_u64_pair();
messages.push(proto::ChannelMessage {
id: row.id.to_proto(),
@@ -113,50 +110,6 @@ impl Database {
});
}
drop(rows);
if let Some(max_id) = max_id {
let has_older_message = observed_channel_messages::Entity::find()
.filter(
observed_channel_messages::Column::UserId
.eq(user_id)
.and(observed_channel_messages::Column::ChannelId.eq(channel_id))
.and(observed_channel_messages::Column::ChannelMessageId.lt(max_id)),
)
.one(&*tx)
.await?
.is_some();
if has_older_message {
observed_channel_messages::Entity::update(
observed_channel_messages::ActiveModel {
user_id: ActiveValue::Unchanged(user_id),
channel_id: ActiveValue::Unchanged(channel_id),
channel_message_id: ActiveValue::Set(max_id),
},
)
.exec(&*tx)
.await?;
} else {
observed_channel_messages::Entity::insert(
observed_channel_messages::ActiveModel {
user_id: ActiveValue::Set(user_id),
channel_id: ActiveValue::Set(channel_id),
channel_message_id: ActiveValue::Set(max_id),
},
)
.on_conflict(
OnConflict::columns([
observed_channel_messages::Column::UserId,
observed_channel_messages::Column::ChannelId,
])
.update_columns([observed_channel_messages::Column::ChannelMessageId])
.to_owned(),
)
.exec(&*tx)
.await?;
}
}
Ok(messages)
})
.await

View File

@@ -130,6 +130,7 @@ impl ChatPanel {
fs,
client,
channel_store,
active_chat: Default::default(),
pending_serialization: Task::ready(None),
message_list,
@@ -328,12 +329,26 @@ impl ChatPanel {
}
fn render_message(&self, ix: usize, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
let message = self.active_chat.as_ref().unwrap().0.read(cx).message(ix);
let (message, is_continuation, is_last) = {
let active_chat = self.active_chat.as_ref().unwrap().0.read(cx);
let last_message = active_chat.message(ix.saturating_sub(1));
let this_message = active_chat.message(ix);
let is_continuation = last_message.id != this_message.id
&& this_message.sender.id == last_message.sender.id;
(
active_chat.message(ix),
is_continuation,
active_chat.message_count() == ix + 1,
)
};
let now = OffsetDateTime::now_utc();
let theme = theme::current(cx);
let style = if message.is_pending() {
&theme.chat_panel.pending_message
} else if is_continuation {
&theme.chat_panel.continuation_message
} else {
&theme.chat_panel.message
};
@@ -349,49 +364,103 @@ impl ChatPanel {
enum DeleteMessage {}
let body = message.body.clone();
Flex::column()
.with_child(
Flex::row()
.with_child(
Label::new(
message.sender.github_login.clone(),
style.sender.text.clone(),
if is_continuation {
Flex::row()
.with_child(Text::new(body, style.body.clone()))
.with_children(message_id_to_remove.map(|id| {
MouseEventHandler::new::<DeleteMessage, _>(id as usize, cx, |mouse_state, _| {
let button_style = theme.chat_panel.icon_button.style_for(mouse_state);
render_icon_button(button_style, "icons/x.svg")
.aligned()
.into_any()
})
.with_padding(Padding::uniform(2.))
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, this, cx| {
this.remove_message(id, cx);
})
.flex_float()
}))
.contained()
.with_style(style.container)
.with_margin_bottom(if is_last {
theme.chat_panel.last_message_bottom_spacing
} else {
0.
})
.into_any()
} else {
Flex::column()
.with_child(
Flex::row()
.with_child(
message
.sender
.avatar
.clone()
.map(|avatar| {
Image::from_data(avatar)
.with_style(theme.collab_panel.channel_avatar)
.into_any()
})
.unwrap_or_else(|| {
Empty::new()
.constrained()
.with_width(
theme.collab_panel.channel_avatar.width.unwrap_or(12.),
)
.into_any()
})
.contained()
.with_margin_right(4.),
)
.contained()
.with_style(style.sender.container),
)
.with_child(
Label::new(
format_timestamp(message.timestamp, now, self.local_timezone),
style.timestamp.text.clone(),
.with_child(
Label::new(
message.sender.github_login.clone(),
style.sender.text.clone(),
)
.contained()
.with_style(style.sender.container),
)
.contained()
.with_style(style.timestamp.container),
)
.with_children(message_id_to_remove.map(|id| {
MouseEventHandler::new::<DeleteMessage, _>(
id as usize,
cx,
|mouse_state, _| {
let button_style =
theme.chat_panel.icon_button.style_for(mouse_state);
render_icon_button(button_style, "icons/x.svg")
.aligned()
.into_any()
},
.with_child(
Label::new(
format_timestamp(message.timestamp, now, self.local_timezone),
style.timestamp.text.clone(),
)
.contained()
.with_style(style.timestamp.container),
)
.with_padding(Padding::uniform(2.))
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, this, cx| {
this.remove_message(id, cx);
})
.flex_float()
})),
)
.with_child(Text::new(body, style.body.clone()))
.contained()
.with_style(style.container)
.into_any()
.with_children(message_id_to_remove.map(|id| {
MouseEventHandler::new::<DeleteMessage, _>(
id as usize,
cx,
|mouse_state, _| {
let button_style =
theme.chat_panel.icon_button.style_for(mouse_state);
render_icon_button(button_style, "icons/x.svg")
.aligned()
.into_any()
},
)
.with_padding(Padding::uniform(2.))
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, this, cx| {
this.remove_message(id, cx);
})
.flex_float()
}))
.align_children_center(),
)
.with_child(Text::new(body, style.body.clone()))
.contained()
.with_style(style.container)
.with_margin_bottom(if is_last {
theme.chat_panel.last_message_bottom_spacing
} else {
0.
})
.into_any()
}
}
fn render_input_box(&self, theme: &Arc<Theme>, cx: &AppContext) -> AnyElement<Self> {

View File

@@ -1937,6 +1937,8 @@ impl CollabPanel {
is_dragged_over = true;
}
let has_messages_notification = channel.unseen_message_id.is_some();
MouseEventHandler::new::<Channel, _>(ix, cx, |state, cx| {
let row_hovered = state.hovered();
@@ -2022,24 +2024,33 @@ impl CollabPanel {
.flex(1., true)
})
.with_child(
MouseEventHandler::new::<ChannelNote, _>(ix, cx, move |_, _| {
MouseEventHandler::new::<ChannelNote, _>(ix, cx, move |mouse_state, _| {
let container_style = collab_theme
.disclosure
.button
.style_for(mouse_state)
.container;
if channel.unseen_message_id.is_some() {
Svg::new("icons/conversations.svg")
.with_color(collab_theme.channel_note_active_color)
.constrained()
.with_width(collab_theme.channel_hash.width)
.contained()
.with_style(container_style)
.with_uniform_padding(4.)
.into_any()
} else if row_hovered {
Svg::new("icons/conversations.svg")
.with_color(collab_theme.channel_hash.color)
.constrained()
.with_width(collab_theme.channel_hash.width)
.contained()
.with_style(container_style)
.with_uniform_padding(4.)
.into_any()
} else {
Empty::new()
.constrained()
.with_width(collab_theme.channel_hash.width)
.into_any()
Empty::new().into_any()
}
})
.on_click(MouseButton::Left, move |_, this, cx| {
@@ -2056,7 +2067,12 @@ impl CollabPanel {
.with_margin_right(4.),
)
.with_child(
MouseEventHandler::new::<ChannelCall, _>(ix, cx, move |_, cx| {
MouseEventHandler::new::<ChannelCall, _>(ix, cx, move |mouse_state, cx| {
let container_style = collab_theme
.disclosure
.button
.style_for(mouse_state)
.container;
if row_hovered || channel.unseen_note_version.is_some() {
Svg::new("icons/file.svg")
.with_color(if channel.unseen_note_version.is_some() {
@@ -2067,6 +2083,8 @@ impl CollabPanel {
.constrained()
.with_width(collab_theme.channel_hash.width)
.contained()
.with_style(container_style)
.with_uniform_padding(4.)
.with_margin_right(collab_theme.channel_hash.container.margin.left)
.with_tooltip::<NotesTooltip>(
ix as usize,
@@ -2076,23 +2094,20 @@ impl CollabPanel {
cx,
)
.into_any()
} else {
} else if has_messages_notification {
Empty::new()
.constrained()
.with_width(collab_theme.channel_hash.width)
.contained()
.with_uniform_padding(4.)
.with_margin_right(collab_theme.channel_hash.container.margin.left)
.into_any()
} else {
Empty::new().into_any()
}
})
.on_click(MouseButton::Left, move |_, this, cx| {
let participants =
this.channel_store.read(cx).channel_participants(channel_id);
if is_active || participants.is_empty() {
this.open_channel_notes(&OpenChannelNotes { channel_id }, cx);
} else {
this.join_channel(channel_id, cx);
};
this.open_channel_notes(&OpenChannelNotes { channel_id }, cx);
}),
)
.align_children_center()

View File

@@ -635,6 +635,8 @@ pub struct ChatPanel {
pub channel_select: ChannelSelect,
pub input_editor: FieldEditor,
pub message: ChatMessage,
pub continuation_message: ChatMessage,
pub last_message_bottom_spacing: f32,
pub pending_message: ChatMessage,
pub sign_in_prompt: Interactive<TextStyle>,
pub icon_button: Interactive<IconButton>,

View File

@@ -78,10 +78,14 @@ fn increment(vim: &mut Vim, mut delta: i32, step: i32, cx: &mut WindowContext) {
2 => format!("{:b}", result),
_ => unreachable!(),
};
if selection.is_empty() {
new_anchors.push((false, snapshot.anchor_after(range.end)))
}
edits.push((range, replace));
edits.push((range.clone(), replace));
}
if selection.is_empty() {
new_anchors.push((false, snapshot.anchor_after(range.end)))
}
} else {
if selection.is_empty() {
new_anchors.push((true, snapshot.anchor_after(start)))
}
}
}
@@ -226,6 +230,8 @@ mod test {
cx.assert_matches_neovim("(ˇ0b10f)", ["ctrl-a"], "(0b1ˇ1f)")
.await;
cx.assert_matches_neovim("ˇ-1", ["ctrl-a"], "ˇ0").await;
cx.assert_matches_neovim("banˇana", ["ctrl-a"], "banˇana")
.await;
}
#[gpui::test]

View File

@@ -13,3 +13,6 @@
{"Put":{"state":"ˇ-1"}}
{"Key":"ctrl-a"}
{"Get":{"state":"ˇ0","mode":"Normal"}}
{"Put":{"state":"banˇana"}}
{"Key":"ctrl-a"}
{"Get":{"state":"banˇana","mode":"Normal"}}

View File

@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
version = "0.107.0"
version = "0.107.1"
publish = false
[lib]

View File

@@ -1 +1 @@
dev
preview

View File

@@ -87,7 +87,19 @@ export default function chat_panel(): any {
...text(layer, "sans", "base", { weight: "bold" }),
},
timestamp: text(layer, "sans", "base", "disabled"),
margin: { bottom: SPACING }
margin: { top: SPACING }
},
last_message_bottom_spacing: SPACING,
continuation_message: {
body: text(layer, "sans", "base"),
sender: {
margin: {
right: 8,
},
...text(layer, "sans", "base", { weight: "bold" }),
},
timestamp: text(layer, "sans", "base", "disabled"),
},
pending_message: {
body: text(layer, "sans", "base"),

View File

@@ -21,6 +21,7 @@ export default function contacts_panel(): any {
...text(theme.lowest, "sans", "base"),
button: icon_button({ variant: "ghost" }),
spacing: 4,
padding: 4,
},
}
}