More progress on collab panel

This commit is contained in:
Conrad Irwin 2023-11-28 14:40:32 -07:00
parent 8ee84249ec
commit a85e0db1f4
5 changed files with 142 additions and 32 deletions

View File

@ -17,6 +17,7 @@ mod contact_finder;
// Client, Contact, User, UserStore,
// };
use contact_finder::ContactFinder;
use rpc::proto;
// use context_menu::{ContextMenu, ContextMenuItem};
// use db::kvp::KEY_VALUE_STORE;
// use drag_and_drop::{DragAndDrop, Draggable};
@ -166,15 +167,17 @@ use editor::Editor;
use feature_flags::{ChannelsAlpha, FeatureFlagAppExt};
use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{
actions, div, img, serde_json, AppContext, AsyncWindowContext, Div, EventEmitter, FocusHandle,
Focusable, FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Render,
RenderOnce, SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView,
actions, div, img, prelude::*, serde_json, AppContext, AsyncWindowContext, Div, EventEmitter,
FocusHandle, Focusable, FocusableView, InteractiveElement, IntoElement, Model, ParentElement,
Render, RenderOnce, SharedString, Styled, Subscription, View, ViewContext, VisualContext,
WeakView,
};
use project::Fs;
use serde_derive::{Deserialize, Serialize};
use settings::Settings;
use ui::{
h_stack, v_stack, Avatar, Button, Icon, IconButton, Label, List, ListHeader, ListItem, Tooltip,
h_stack, v_stack, Avatar, Button, Color, Icon, IconButton, Label, List, ListHeader, ListItem,
Toggle, Tooltip,
};
use util::{maybe, ResultExt};
use workspace::{
@ -183,7 +186,7 @@ use workspace::{
Workspace,
};
use crate::CollaborationPanelSettings;
use crate::{face_pile::FacePile, CollaborationPanelSettings};
pub fn init(cx: &mut AppContext) {
cx.observe_new_views(|workspace: &mut Workspace, _| {
@ -309,7 +312,7 @@ pub struct CollabPanel {
// channel_name_editor: ViewHandle<Editor>,
channel_editing_state: Option<ChannelEditingState>,
entries: Vec<ListEntry>,
// selection: Option<usize>,
selection: Option<usize>,
channel_store: Model<ChannelStore>,
user_store: Model<UserStore>,
client: Arc<Client>,
@ -600,7 +603,7 @@ impl CollabPanel {
filter_editor,
entries: Vec::default(),
channel_editing_state: None,
// selection: None,
selection: None,
channel_store: ChannelStore::global(cx),
user_store: workspace.user_store().clone(),
// project: workspace.project().clone(),
@ -2357,14 +2360,14 @@ impl CollabPanel {
// self.deploy_channel_context_menu(None, &channel.clone(), self.selection.unwrap(), cx);
// }
// fn selected_channel(&self) -> Option<&Arc<Channel>> {
// self.selection
// .and_then(|ix| self.entries.get(ix))
// .and_then(|entry| match entry {
// ListEntry::Channel { channel, .. } => Some(channel),
// _ => None,
// })
// }
fn selected_channel(&self) -> Option<&Arc<Channel>> {
self.selection
.and_then(|ix| self.entries.get(ix))
.and_then(|entry| match entry {
ListEntry::Channel { channel, .. } => Some(channel),
_ => None,
})
}
// fn show_channel_modal(
// &mut self,
@ -3019,7 +3022,123 @@ impl CollabPanel {
cx: &mut ViewContext<Self>,
) -> impl IntoElement {
let channel_id = channel.id;
ListItem::new(channel_id as usize).child(Label::new(channel.name.clone()))
let is_public = self
.channel_store
.read(cx)
.channel_for_id(channel_id)
.map(|channel| channel.visibility)
== Some(proto::ChannelVisibility::Public);
let other_selected = self.selected_channel().map(|channel| channel.id) == Some(channel.id);
let disclosed = has_children
.then(|| !self.collapsed_channels.binary_search(&channel.id).is_ok())
.unwrap_or(false);
let is_active = maybe!({
let call_channel = ActiveCall::global(cx)
.read(cx)
.room()?
.read(cx)
.channel_id()?;
Some(call_channel == channel_id)
})
.unwrap_or(false);
let has_messages_notification = channel.unseen_message_id.is_some() || true;
let has_notes_notification = channel.unseen_note_version.is_some();
const FACEPILE_LIMIT: usize = 3;
let participants = self.channel_store.read(cx).channel_participants(channel_id);
let face_pile = if !participants.is_empty() {
let extra_count = participants.len().saturating_sub(FACEPILE_LIMIT);
let result = FacePile {
faces: participants
.iter()
.filter_map(|user| Some(Avatar::data(user.avatar.clone()?).into_any_element()))
.take(FACEPILE_LIMIT)
.chain(if extra_count > 0 {
Some(Label::new(format!("+{}", extra_count)).into_any_element())
} else {
None
})
.collect::<Vec<_>>(),
};
Some(result)
} else {
None
};
div().group("").child(
ListItem::new(channel_id as usize)
.indent_level(depth)
.left_icon(if is_public { Icon::Public } else { Icon::Hash })
.selected(is_selected || is_active)
.child(
h_stack()
.w_full()
.justify_between()
.child(
div()
.id(channel_id as usize)
.child(Label::new(channel.name.clone()))
.children(face_pile.map(|face_pile| face_pile.render(cx)))
.tooltip(|cx| Tooltip::text("Join channel", cx)),
)
.child(
h_stack()
.child(
div()
.id("channel_chat")
.bg(gpui::blue())
.when(!has_messages_notification, |el| el.invisible())
.group_hover("", |style| style.visible())
.child(
IconButton::new("test_chat", Icon::MessageBubbles)
.color(if has_messages_notification {
Color::Default
} else {
Color::Muted
}),
)
.tooltip(|cx| Tooltip::text("Open channel chat", cx)),
)
.child(
div()
.id("channel_notes")
.when(!has_notes_notification, |el| el.invisible())
.group_hover("", |style| style.visible())
.child(
div().child("Notes").id("test_notes").tooltip(|cx| {
Tooltip::text("Open channel notes", cx)
}),
), // .child(
// IconButton::new("channel_notes", Icon::File)
// .color(if has_notes_notification {
// Color::Default
// } else {
// Color::Muted
// })
// .tooltip(|cx| {
// Tooltip::text("Open channel notes", cx)
// }),
// ),
),
),
)
.toggle(if has_children {
Toggle::Toggled(disclosed)
} else {
Toggle::NotToggleable
})
.on_click(cx.listener(|this, _, cx| todo!()))
.on_secondary_mouse_down(cx.listener(|this, _, cx| {
todo!() // open context menu
})),
)
// let channel_id = channel.id;
// let collab_theme = &theme.collab_panel;
// let is_public = self
@ -3032,18 +3151,6 @@ impl CollabPanel {
// let disclosed =
// has_children.then(|| !self.collapsed_channels.binary_search(&channel.id).is_ok());
// let is_active = maybe!({
// let call_channel = ActiveCall::global(cx)
// .read(cx)
// .room()?
// .read(cx)
// .channel_id()?;
// Some(call_channel == channel_id)
// })
// .unwrap_or(false);
// const FACEPILE_LIMIT: usize = 3;
// enum ChannelCall {}
// enum ChannelNote {}
// enum NotesTooltip {}

View File

@ -3,8 +3,8 @@ use gpui::{
};
#[derive(Default)]
pub(crate) struct FacePile {
faces: Vec<AnyElement>,
pub struct FacePile {
pub faces: Vec<AnyElement>,
}
impl RenderOnce for FacePile {

View File

@ -105,7 +105,6 @@ impl Element for Overlay {
origin: Point::zero(),
size: cx.viewport_size(),
};
dbg!(limits);
match self.fit_mode {
OverlayFitMode::SnapToWindow => {

View File

@ -63,6 +63,7 @@ pub enum Icon {
Mic,
MicMute,
Plus,
Public,
Quote,
Replace,
ReplaceAll,
@ -134,6 +135,7 @@ impl Icon {
Icon::Mic => "icons/mic.svg",
Icon::MicMute => "icons/mic-mute.svg",
Icon::Plus => "icons/plus.svg",
Icon::Public => "icons/public.svg",
Icon::Quote => "icons/quote.svg",
Icon::Replace => "icons/replace.svg",
Icon::ReplaceAll => "icons/replace_all.svg",

View File

@ -65,7 +65,9 @@ impl RenderOnce for IconButton {
}
}
button
// todo! this extra wrapping div is to work around a bug
// where tooltips otherwise don't show up.
div().id(self.id.clone()).child(button)
}
}