Show channel notes in current call section of collab panel
Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
parent
1ae54ca620
commit
a327320f7d
1 changed files with 146 additions and 42 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue