Show channel notes in current call section of collab panel

Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
Max Brunsfeld 2023-08-24 15:00:54 -07:00
parent 1ae54ca620
commit a327320f7d

View file

@ -18,13 +18,14 @@ use gpui::{
MouseEventHandler, Orientation, OverlayPositionMode, Padding, ParentElement, SafeStylable,
Stack, Svg,
},
fonts::TextStyle,
geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
},
impl_actions,
platform::{CursorStyle, MouseButton, PromptLevel},
serde_json, AnyElement, AppContext, AsyncAppContext, Element, Entity, ModelHandle,
serde_json, AnyElement, AppContext, AsyncAppContext, Element, Entity, FontCache, ModelHandle,
Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
};
use menu::{Confirm, SelectNext, SelectPrev};
@ -183,6 +184,7 @@ pub struct CollabPanel {
#[derive(Serialize, Deserialize)]
struct SerializedChannelsPanel {
width: Option<f32>,
collapsed_channels: Vec<ChannelId>,
}
#[derive(Debug)]
@ -227,6 +229,9 @@ enum ListEntry {
channel: Arc<Channel>,
depth: usize,
},
ChannelNotes {
channel_id: ChannelId,
},
ChannelEditor {
depth: usize,
},
@ -370,6 +375,12 @@ impl CollabPanel {
return channel_row;
}
}
ListEntry::ChannelNotes { channel_id } => this.render_channel_notes(
*channel_id,
&theme.collab_panel,
is_selected,
cx,
),
ListEntry::ChannelInvite(channel) => Self::render_channel_invite(
channel.clone(),
this.channel_store.clone(),
@ -509,6 +520,7 @@ impl CollabPanel {
if let Some(serialized_panel) = serialized_panel {
panel.update(cx, |panel, cx| {
panel.width = serialized_panel.width;
panel.collapsed_channels = serialized_panel.collapsed_channels;
cx.notify();
});
}
@ -519,12 +531,16 @@ impl CollabPanel {
fn serialize(&mut self, cx: &mut ViewContext<Self>) {
let width = self.width;
let collapsed_channels = self.collapsed_channels.clone();
self.pending_serialization = cx.background().spawn(
async move {
KEY_VALUE_STORE
.write_kvp(
COLLABORATION_PANEL_KEY.into(),
serde_json::to_string(&SerializedChannelsPanel { width })?,
serde_json::to_string(&SerializedChannelsPanel {
width,
collapsed_channels,
})?,
)
.await?;
anyhow::Ok(())
@ -548,6 +564,10 @@ impl CollabPanel {
if !self.collapsed_sections.contains(&Section::ActiveCall) {
let room = room.read(cx);
if let Some(channel_id) = room.channel_id() {
self.entries.push(ListEntry::ChannelNotes { channel_id })
}
// Populate the active user.
if let Some(user) = user_store.current_user() {
self.match_candidates.clear();
@ -1007,25 +1027,19 @@ impl CollabPanel {
) -> AnyElement<Self> {
enum JoinProject {}
let font_cache = cx.font_cache();
let host_avatar_height = theme
let host_avatar_width = theme
.contact_avatar
.width
.or(theme.contact_avatar.height)
.unwrap_or(0.);
let row = &theme.project_row.inactive_state().default;
let tree_branch = theme.tree_branch;
let line_height = row.name.text.line_height(font_cache);
let cap_height = row.name.text.cap_height(font_cache);
let baseline_offset =
row.name.text.baseline_offset(font_cache) + (theme.row_height - line_height) / 2.;
let project_name = if worktree_root_names.is_empty() {
"untitled".to_string()
} else {
worktree_root_names.join(", ")
};
MouseEventHandler::new::<JoinProject, _>(project_id as usize, cx, |mouse_state, _| {
MouseEventHandler::new::<JoinProject, _>(project_id as usize, cx, |mouse_state, cx| {
let tree_branch = *tree_branch.in_state(is_selected).style_for(mouse_state);
let row = theme
.project_row
@ -1033,39 +1047,20 @@ impl CollabPanel {
.style_for(mouse_state);
Flex::row()
.with_child(render_tree_branch(
tree_branch,
&row.name.text,
is_last,
vec2f(host_avatar_width, theme.row_height),
cx.font_cache(),
))
.with_child(
Stack::new()
.with_child(Canvas::new(move |scene, bounds, _, _, _| {
let start_x =
bounds.min_x() + (bounds.width() / 2.) - (tree_branch.width / 2.);
let end_x = bounds.max_x();
let start_y = bounds.min_y();
let end_y = bounds.min_y() + baseline_offset - (cap_height / 2.);
scene.push_quad(gpui::Quad {
bounds: RectF::from_points(
vec2f(start_x, start_y),
vec2f(
start_x + tree_branch.width,
if is_last { end_y } else { bounds.max_y() },
),
),
background: Some(tree_branch.color),
border: gpui::Border::default(),
corner_radii: (0.).into(),
});
scene.push_quad(gpui::Quad {
bounds: RectF::from_points(
vec2f(start_x, end_y),
vec2f(end_x, end_y + tree_branch.width),
),
background: Some(tree_branch.color),
border: gpui::Border::default(),
corner_radii: (0.).into(),
});
}))
Svg::new("icons/file_icons/folder.svg")
.with_color(theme.channel_hash.color)
.constrained()
.with_width(host_avatar_height),
.with_width(theme.channel_hash.width)
.aligned()
.left(),
)
.with_child(
Label::new(project_name, row.name.text.clone())
@ -1240,7 +1235,7 @@ impl CollabPanel {
});
if let Some(name) = channel_name {
Cow::Owned(format!("Current Call - #{}", name))
Cow::Owned(format!("#{}", name))
} else {
Cow::Borrowed("Current Call")
}
@ -1676,6 +1671,61 @@ impl CollabPanel {
.into_any()
}
fn render_channel_notes(
&self,
channel_id: ChannelId,
theme: &theme::CollabPanel,
is_selected: bool,
cx: &mut ViewContext<Self>,
) -> AnyElement<Self> {
enum ChannelNotes {}
let host_avatar_width = theme
.contact_avatar
.width
.or(theme.contact_avatar.height)
.unwrap_or(0.);
MouseEventHandler::new::<ChannelNotes, _>(channel_id as usize, cx, |state, cx| {
let tree_branch = *theme.tree_branch.in_state(is_selected).style_for(state);
let row = theme.project_row.in_state(is_selected).style_for(state);
Flex::<Self>::row()
.with_child(render_tree_branch(
tree_branch,
&row.name.text,
true,
vec2f(host_avatar_width, theme.row_height),
cx.font_cache(),
))
.with_child(
Svg::new("icons/radix/file.svg")
.with_color(theme.channel_hash.color)
.constrained()
.with_width(theme.channel_hash.width)
.aligned()
.left(),
)
.with_child(
Label::new("notes", theme.channel_name.text.clone())
.contained()
.with_style(theme.channel_name.container)
.aligned()
.left()
.flex(1., true),
)
.constrained()
.with_height(theme.row_height)
.contained()
.with_style(*theme.channel_row.style_for(is_selected, state))
.with_padding_left(theme.channel_row.default_style().padding.left)
})
.on_click(MouseButton::Left, move |_, this, cx| {
this.open_channel_buffer(&OpenChannelBuffer { channel_id }, cx);
})
.with_cursor_style(CursorStyle::PointingHand)
.into_any()
}
fn render_channel_invite(
channel: Arc<Channel>,
channel_store: ModelHandle<ChannelStore>,
@ -2114,6 +2164,7 @@ impl CollabPanel {
self.collapsed_channels.insert(ix, channel_id);
}
};
self.serialize(cx);
self.update_entries(true, cx);
cx.notify();
cx.focus_self();
@ -2392,6 +2443,51 @@ impl CollabPanel {
}
}
fn render_tree_branch(
branch_style: theme::TreeBranch,
row_style: &TextStyle,
is_last: bool,
size: Vector2F,
font_cache: &FontCache,
) -> gpui::elements::ConstrainedBox<CollabPanel> {
let line_height = row_style.line_height(font_cache);
let cap_height = row_style.cap_height(font_cache);
let baseline_offset = row_style.baseline_offset(font_cache) + (size.y() - line_height) / 2.;
Canvas::new(move |scene, bounds, _, _, _| {
scene.paint_layer(None, |scene| {
let start_x = bounds.min_x() + (bounds.width() / 2.) - (branch_style.width / 2.);
let end_x = bounds.max_x();
let start_y = bounds.min_y();
let end_y = bounds.min_y() + baseline_offset - (cap_height / 2.);
scene.push_quad(gpui::Quad {
bounds: RectF::from_points(
vec2f(start_x, start_y),
vec2f(
start_x + branch_style.width,
if is_last { end_y } else { bounds.max_y() },
),
),
background: Some(branch_style.color),
border: gpui::Border::default(),
corner_radii: (0.).into(),
});
scene.push_quad(gpui::Quad {
bounds: RectF::from_points(
vec2f(start_x, end_y),
vec2f(end_x, end_y + branch_style.width),
),
background: Some(branch_style.color),
border: gpui::Border::default(),
corner_radii: (0.).into(),
});
})
})
.constrained()
.with_width(size.x())
}
impl View for CollabPanel {
fn ui_name() -> &'static str {
"CollabPanel"
@ -2601,6 +2697,14 @@ impl PartialEq for ListEntry {
return channel_1.id == channel_2.id && depth_1 == depth_2;
}
}
ListEntry::ChannelNotes { channel_id } => {
if let ListEntry::ChannelNotes {
channel_id: other_id,
} = other
{
return channel_id == other_id;
}
}
ListEntry::ChannelInvite(channel_1) => {
if let ListEntry::ChannelInvite(channel_2) = other {
return channel_1.id == channel_2.id;