Put channel call participants back in channel row
Open both the channel notes and the channel chat when clicking a channel
This commit is contained in:
parent
fe6f0a253b
commit
f53a1ee46d
4 changed files with 109 additions and 187 deletions
|
@ -196,10 +196,15 @@ impl ChannelStore {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Asynchronously open a given resource associated with a channel.
|
||||||
|
///
|
||||||
|
/// Make sure that the resource is only opened once, even if this method
|
||||||
|
/// is called multiple times with the same channel id while the first task
|
||||||
|
/// is still running.
|
||||||
fn open_channel_resource<T: Entity, F, Fut>(
|
fn open_channel_resource<T: Entity, F, Fut>(
|
||||||
&mut self,
|
&mut self,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
map: fn(&mut Self) -> &mut HashMap<ChannelId, OpenedModelHandle<T>>,
|
get_map: fn(&mut Self) -> &mut HashMap<ChannelId, OpenedModelHandle<T>>,
|
||||||
load: F,
|
load: F,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<ModelHandle<T>>>
|
) -> Task<Result<ModelHandle<T>>>
|
||||||
|
@ -207,21 +212,20 @@ impl ChannelStore {
|
||||||
F: 'static + FnOnce(Arc<Channel>, AsyncAppContext) -> Fut,
|
F: 'static + FnOnce(Arc<Channel>, AsyncAppContext) -> Fut,
|
||||||
Fut: Future<Output = Result<ModelHandle<T>>>,
|
Fut: Future<Output = Result<ModelHandle<T>>>,
|
||||||
{
|
{
|
||||||
// Make sure that a given channel resource is only opened once per
|
|
||||||
// app instance, even if this method is called multiple times
|
|
||||||
// with the same channel id while the first task is still running.
|
|
||||||
let task = loop {
|
let task = loop {
|
||||||
match map(self).entry(channel_id) {
|
match get_map(self).entry(channel_id) {
|
||||||
hash_map::Entry::Occupied(e) => match e.get() {
|
hash_map::Entry::Occupied(e) => match e.get() {
|
||||||
OpenedModelHandle::Open(buffer) => {
|
OpenedModelHandle::Open(model) => {
|
||||||
if let Some(buffer) = buffer.upgrade(cx) {
|
if let Some(model) = model.upgrade(cx) {
|
||||||
break Task::ready(Ok(buffer)).shared();
|
break Task::ready(Ok(model)).shared();
|
||||||
} else {
|
} else {
|
||||||
map(self).remove(&channel_id);
|
get_map(self).remove(&channel_id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpenedModelHandle::Loading(task) => break task.clone(),
|
OpenedModelHandle::Loading(task) => {
|
||||||
|
break task.clone();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
hash_map::Entry::Vacant(e) => {
|
hash_map::Entry::Vacant(e) => {
|
||||||
let task = cx
|
let task = cx
|
||||||
|
@ -235,25 +239,21 @@ impl ChannelStore {
|
||||||
load(channel, cx).await.map_err(Arc::new)
|
load(channel, cx).await.map_err(Arc::new)
|
||||||
})
|
})
|
||||||
.shared();
|
.shared();
|
||||||
|
|
||||||
e.insert(OpenedModelHandle::Loading(task.clone()));
|
e.insert(OpenedModelHandle::Loading(task.clone()));
|
||||||
cx.spawn({
|
cx.spawn({
|
||||||
let task = task.clone();
|
let task = task.clone();
|
||||||
|this, mut cx| async move {
|
|this, mut cx| async move {
|
||||||
let result = task.await;
|
let result = task.await;
|
||||||
this.update(&mut cx, |this, cx| match result {
|
this.update(&mut cx, |this, _| match result {
|
||||||
Ok(buffer) => {
|
Ok(model) => {
|
||||||
cx.observe_release(&buffer, move |this, _, _| {
|
get_map(this).insert(
|
||||||
this.opened_buffers.remove(&channel_id);
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
map(this).insert(
|
|
||||||
channel_id,
|
channel_id,
|
||||||
OpenedModelHandle::Open(buffer.downgrade()),
|
OpenedModelHandle::Open(model.downgrade()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(_) => {
|
||||||
log::error!("failed to open channel buffer {error:?}");
|
get_map(this).remove(&channel_id);
|
||||||
map(this).remove(&channel_id);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ impl ChannelView {
|
||||||
|
|
||||||
cx.spawn(|mut cx| async move {
|
cx.spawn(|mut cx| async move {
|
||||||
let channel_buffer = channel_buffer.await?;
|
let channel_buffer = channel_buffer.await?;
|
||||||
|
|
||||||
let markdown = markdown.await?;
|
let markdown = markdown.await?;
|
||||||
channel_buffer.update(&mut cx, |buffer, cx| {
|
channel_buffer.update(&mut cx, |buffer, cx| {
|
||||||
buffer.buffer().update(cx, |buffer, cx| {
|
buffer.buffer().update(cx, |buffer, cx| {
|
||||||
|
@ -75,7 +76,6 @@ impl ChannelView {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let buffer = channel_buffer.read(cx).buffer();
|
let buffer = channel_buffer.read(cx).buffer();
|
||||||
// buffer.update(cx, |buffer, cx| buffer.set_language(language, cx));
|
|
||||||
let editor = cx.add_view(|cx| Editor::for_buffer(buffer, None, cx));
|
let editor = cx.add_view(|cx| Editor::for_buffer(buffer, None, cx));
|
||||||
let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()));
|
let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()));
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ const CHAT_PANEL_KEY: &'static str = "ChatPanel";
|
||||||
pub struct ChatPanel {
|
pub struct ChatPanel {
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
channel_store: ModelHandle<ChannelStore>,
|
channel_store: ModelHandle<ChannelStore>,
|
||||||
active_channel: Option<(ModelHandle<ChannelChat>, Subscription)>,
|
active_chat: Option<(ModelHandle<ChannelChat>, Subscription)>,
|
||||||
message_list: ListState<ChatPanel>,
|
message_list: ListState<ChatPanel>,
|
||||||
input_editor: ViewHandle<Editor>,
|
input_editor: ViewHandle<Editor>,
|
||||||
channel_select: ViewHandle<Select>,
|
channel_select: ViewHandle<Select>,
|
||||||
|
@ -105,7 +105,7 @@ impl ChatPanel {
|
||||||
|
|
||||||
let mut message_list =
|
let mut message_list =
|
||||||
ListState::<Self>::new(0, Orientation::Bottom, 1000., move |this, ix, cx| {
|
ListState::<Self>::new(0, Orientation::Bottom, 1000., move |this, ix, cx| {
|
||||||
let message = this.active_channel.as_ref().unwrap().0.read(cx).message(ix);
|
let message = this.active_chat.as_ref().unwrap().0.read(cx).message(ix);
|
||||||
this.render_message(message, cx)
|
this.render_message(message, cx)
|
||||||
});
|
});
|
||||||
message_list.set_scroll_handler(|visible_range, this, cx| {
|
message_list.set_scroll_handler(|visible_range, this, cx| {
|
||||||
|
@ -119,7 +119,7 @@ impl ChatPanel {
|
||||||
fs,
|
fs,
|
||||||
client,
|
client,
|
||||||
channel_store,
|
channel_store,
|
||||||
active_channel: Default::default(),
|
active_chat: Default::default(),
|
||||||
pending_serialization: Task::ready(None),
|
pending_serialization: Task::ready(None),
|
||||||
message_list,
|
message_list,
|
||||||
input_editor,
|
input_editor,
|
||||||
|
@ -151,6 +151,7 @@ impl ChatPanel {
|
||||||
|
|
||||||
cx.observe(&this.channel_select, |this, channel_select, cx| {
|
cx.observe(&this.channel_select, |this, channel_select, cx| {
|
||||||
let selected_ix = channel_select.read(cx).selected_index();
|
let selected_ix = channel_select.read(cx).selected_index();
|
||||||
|
|
||||||
let selected_channel_id = this
|
let selected_channel_id = this
|
||||||
.channel_store
|
.channel_store
|
||||||
.read(cx)
|
.read(cx)
|
||||||
|
@ -216,14 +217,14 @@ impl ChatPanel {
|
||||||
fn init_active_channel(&mut self, cx: &mut ViewContext<Self>) {
|
fn init_active_channel(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
let channel_count = self.channel_store.read(cx).channel_count();
|
let channel_count = self.channel_store.read(cx).channel_count();
|
||||||
self.message_list.reset(0);
|
self.message_list.reset(0);
|
||||||
self.active_channel = None;
|
self.active_chat = None;
|
||||||
self.channel_select.update(cx, |select, cx| {
|
self.channel_select.update(cx, |select, cx| {
|
||||||
select.set_item_count(channel_count, cx);
|
select.set_item_count(channel_count, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_active_channel(&mut self, chat: ModelHandle<ChannelChat>, cx: &mut ViewContext<Self>) {
|
fn set_active_chat(&mut self, chat: ModelHandle<ChannelChat>, cx: &mut ViewContext<Self>) {
|
||||||
if self.active_channel.as_ref().map(|e| &e.0) != Some(&chat) {
|
if self.active_chat.as_ref().map(|e| &e.0) != Some(&chat) {
|
||||||
let id = chat.read(cx).channel().id;
|
let id = chat.read(cx).channel().id;
|
||||||
{
|
{
|
||||||
let chat = chat.read(cx);
|
let chat = chat.read(cx);
|
||||||
|
@ -234,7 +235,7 @@ impl ChatPanel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let subscription = cx.subscribe(&chat, Self::channel_did_change);
|
let subscription = cx.subscribe(&chat, Self::channel_did_change);
|
||||||
self.active_channel = Some((chat, subscription));
|
self.active_chat = Some((chat, subscription));
|
||||||
self.channel_select.update(cx, |select, cx| {
|
self.channel_select.update(cx, |select, cx| {
|
||||||
if let Some(ix) = self.channel_store.read(cx).index_of_channel(id) {
|
if let Some(ix) = self.channel_store.read(cx).index_of_channel(id) {
|
||||||
select.set_selected_index(ix, cx);
|
select.set_selected_index(ix, cx);
|
||||||
|
@ -275,7 +276,7 @@ impl ChatPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_active_channel_messages(&self) -> AnyElement<Self> {
|
fn render_active_channel_messages(&self) -> AnyElement<Self> {
|
||||||
let messages = if self.active_channel.is_some() {
|
let messages = if self.active_chat.is_some() {
|
||||||
List::new(self.message_list.clone()).into_any()
|
List::new(self.message_list.clone()).into_any()
|
||||||
} else {
|
} else {
|
||||||
Empty::new().into_any()
|
Empty::new().into_any()
|
||||||
|
@ -396,15 +397,15 @@ impl ChatPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
fn send(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||||
if let Some((channel, _)) = self.active_channel.as_ref() {
|
if let Some((chat, _)) = self.active_chat.as_ref() {
|
||||||
let body = self.input_editor.update(cx, |editor, cx| {
|
let body = self.input_editor.update(cx, |editor, cx| {
|
||||||
let body = editor.text(cx);
|
let body = editor.text(cx);
|
||||||
editor.clear(cx);
|
editor.clear(cx);
|
||||||
body
|
body
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(task) = channel
|
if let Some(task) = chat
|
||||||
.update(cx, |channel, cx| channel.send_message(body, cx))
|
.update(cx, |chat, cx| chat.send_message(body, cx))
|
||||||
.log_err()
|
.log_err()
|
||||||
{
|
{
|
||||||
task.detach();
|
task.detach();
|
||||||
|
@ -413,8 +414,8 @@ impl ChatPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_more_messages(&mut self, _: &LoadMoreMessages, cx: &mut ViewContext<Self>) {
|
fn load_more_messages(&mut self, _: &LoadMoreMessages, cx: &mut ViewContext<Self>) {
|
||||||
if let Some((channel, _)) = self.active_channel.as_ref() {
|
if let Some((chat, _)) = self.active_chat.as_ref() {
|
||||||
channel.update(cx, |channel, cx| {
|
chat.update(cx, |channel, cx| {
|
||||||
channel.load_more_messages(cx);
|
channel.load_more_messages(cx);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -425,13 +426,19 @@ impl ChatPanel {
|
||||||
selected_channel_id: u64,
|
selected_channel_id: u64,
|
||||||
cx: &mut ViewContext<ChatPanel>,
|
cx: &mut ViewContext<ChatPanel>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
|
if let Some((chat, _)) = &self.active_chat {
|
||||||
|
if chat.read(cx).channel().id == selected_channel_id {
|
||||||
|
return Task::ready(Ok(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let open_chat = self.channel_store.update(cx, |store, cx| {
|
let open_chat = self.channel_store.update(cx, |store, cx| {
|
||||||
store.open_channel_chat(selected_channel_id, cx)
|
store.open_channel_chat(selected_channel_id, cx)
|
||||||
});
|
});
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let chat = open_chat.await?;
|
let chat = open_chat.await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.set_active_channel(chat, cx);
|
this.set_active_chat(chat, cx);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ struct RenameChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct OpenChannelBuffer {
|
struct OpenChannelNotes {
|
||||||
channel_id: u64,
|
channel_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ impl_actions!(
|
||||||
ManageMembers,
|
ManageMembers,
|
||||||
RenameChannel,
|
RenameChannel,
|
||||||
ToggleCollapse,
|
ToggleCollapse,
|
||||||
OpenChannelBuffer
|
OpenChannelNotes
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ pub fn init(cx: &mut AppContext) {
|
||||||
cx.add_action(CollabPanel::toggle_channel_collapsed);
|
cx.add_action(CollabPanel::toggle_channel_collapsed);
|
||||||
cx.add_action(CollabPanel::collapse_selected_channel);
|
cx.add_action(CollabPanel::collapse_selected_channel);
|
||||||
cx.add_action(CollabPanel::expand_selected_channel);
|
cx.add_action(CollabPanel::expand_selected_channel);
|
||||||
cx.add_action(CollabPanel::open_channel_buffer);
|
cx.add_action(CollabPanel::open_channel_notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -226,10 +226,6 @@ enum ListEntry {
|
||||||
channel: Arc<Channel>,
|
channel: Arc<Channel>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
},
|
},
|
||||||
ChannelCall {
|
|
||||||
channel: Arc<Channel>,
|
|
||||||
depth: usize,
|
|
||||||
},
|
|
||||||
ChannelNotes {
|
ChannelNotes {
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
},
|
},
|
||||||
|
@ -369,13 +365,6 @@ impl CollabPanel {
|
||||||
return channel_row;
|
return channel_row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListEntry::ChannelCall { channel, depth } => this.render_channel_call(
|
|
||||||
&*channel,
|
|
||||||
*depth,
|
|
||||||
&theme.collab_panel,
|
|
||||||
is_selected,
|
|
||||||
cx,
|
|
||||||
),
|
|
||||||
ListEntry::ChannelNotes { channel_id } => this.render_channel_notes(
|
ListEntry::ChannelNotes { channel_id } => this.render_channel_notes(
|
||||||
*channel_id,
|
*channel_id,
|
||||||
&theme.collab_panel,
|
&theme.collab_panel,
|
||||||
|
@ -751,12 +740,6 @@ impl CollabPanel {
|
||||||
channel: channel.clone(),
|
channel: channel.clone(),
|
||||||
depth,
|
depth,
|
||||||
});
|
});
|
||||||
if !channel_store.channel_participants(channel.id).is_empty() {
|
|
||||||
self.entries.push(ListEntry::ChannelCall {
|
|
||||||
channel: channel.clone(),
|
|
||||||
depth,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1566,10 +1549,23 @@ impl CollabPanel {
|
||||||
let disclosed =
|
let disclosed =
|
||||||
has_children.then(|| !self.collapsed_channels.binary_search(&channel_id).is_ok());
|
has_children.then(|| !self.collapsed_channels.binary_search(&channel_id).is_ok());
|
||||||
|
|
||||||
|
let is_active = iife!({
|
||||||
|
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 ChannelCall {}
|
||||||
enum ChannelNotes {}
|
|
||||||
|
|
||||||
MouseEventHandler::new::<Channel, _>(channel.id as usize, cx, |state, cx| {
|
MouseEventHandler::new::<Channel, _>(channel.id as usize, cx, |state, cx| {
|
||||||
|
let row_hovered = state.hovered();
|
||||||
|
|
||||||
Flex::<Self>::row()
|
Flex::<Self>::row()
|
||||||
.with_child(
|
.with_child(
|
||||||
Svg::new("icons/hash.svg")
|
Svg::new("icons/hash.svg")
|
||||||
|
@ -1588,29 +1584,49 @@ impl CollabPanel {
|
||||||
.flex(1., true),
|
.flex(1., true),
|
||||||
)
|
)
|
||||||
.with_child(
|
.with_child(
|
||||||
MouseEventHandler::new::<ChannelCall, _>(channel_id as usize, cx, |_, _| {
|
MouseEventHandler::new::<ChannelCall, _>(
|
||||||
Svg::new("icons/radix/speaker-loud.svg")
|
channel.id as usize,
|
||||||
.with_color(theme.channel_hash.color)
|
cx,
|
||||||
.constrained()
|
move |_, cx| {
|
||||||
.with_width(theme.channel_hash.width)
|
let participants =
|
||||||
.aligned()
|
self.channel_store.read(cx).channel_participants(channel_id);
|
||||||
.right()
|
if !participants.is_empty() {
|
||||||
})
|
let extra_count = participants.len().saturating_sub(FACEPILE_LIMIT);
|
||||||
|
|
||||||
|
FacePile::new(theme.face_overlap)
|
||||||
|
.with_children(
|
||||||
|
participants
|
||||||
|
.iter()
|
||||||
|
.filter_map(|user| {
|
||||||
|
Some(
|
||||||
|
Image::from_data(user.avatar.clone()?)
|
||||||
|
.with_style(theme.channel_avatar),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.take(FACEPILE_LIMIT),
|
||||||
|
)
|
||||||
|
.with_children((extra_count > 0).then(|| {
|
||||||
|
Label::new(
|
||||||
|
format!("+{}", extra_count),
|
||||||
|
theme.extra_participant_label.text.clone(),
|
||||||
|
)
|
||||||
|
.contained()
|
||||||
|
.with_style(theme.extra_participant_label.container)
|
||||||
|
}))
|
||||||
|
.into_any()
|
||||||
|
} else if row_hovered {
|
||||||
|
Svg::new("icons/radix/speaker-loud.svg")
|
||||||
|
.with_color(theme.channel_hash.color)
|
||||||
|
.constrained()
|
||||||
|
.with_width(theme.channel_hash.width)
|
||||||
|
.into_any()
|
||||||
|
} else {
|
||||||
|
Empty::new().into_any()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
.on_click(MouseButton::Left, move |_, this, cx| {
|
||||||
this.join_channel_call(channel_id, cx)
|
this.join_channel_call(channel_id, cx);
|
||||||
}),
|
|
||||||
)
|
|
||||||
.with_child(
|
|
||||||
MouseEventHandler::new::<ChannelNotes, _>(channel_id as usize, cx, |_, _| {
|
|
||||||
Svg::new("icons/radix/file.svg")
|
|
||||||
.with_color(theme.channel_hash.color)
|
|
||||||
.constrained()
|
|
||||||
.with_width(theme.channel_hash.width)
|
|
||||||
.aligned()
|
|
||||||
.right()
|
|
||||||
})
|
|
||||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
|
||||||
this.open_channel_buffer(&OpenChannelBuffer { channel_id }, cx);
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.align_children_center()
|
.align_children_center()
|
||||||
|
@ -1622,7 +1638,7 @@ impl CollabPanel {
|
||||||
.constrained()
|
.constrained()
|
||||||
.with_height(theme.row_height)
|
.with_height(theme.row_height)
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(*theme.channel_row.style_for(is_selected, state))
|
.with_style(*theme.channel_row.style_for(is_selected || is_active, state))
|
||||||
.with_padding_left(
|
.with_padding_left(
|
||||||
theme.channel_row.default_style().padding.left
|
theme.channel_row.default_style().padding.left
|
||||||
+ theme.channel_indent * depth as f32,
|
+ theme.channel_indent * depth as f32,
|
||||||
|
@ -1638,94 +1654,6 @@ impl CollabPanel {
|
||||||
.into_any()
|
.into_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_channel_call(
|
|
||||||
&self,
|
|
||||||
channel: &Channel,
|
|
||||||
depth: usize,
|
|
||||||
theme: &theme::CollabPanel,
|
|
||||||
is_selected: bool,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) -> AnyElement<Self> {
|
|
||||||
let channel_id = channel.id;
|
|
||||||
|
|
||||||
let is_active = iife!({
|
|
||||||
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 = 5;
|
|
||||||
|
|
||||||
enum ChannelCall {}
|
|
||||||
|
|
||||||
let host_avatar_width = theme
|
|
||||||
.contact_avatar
|
|
||||||
.width
|
|
||||||
.or(theme.contact_avatar.height)
|
|
||||||
.unwrap_or(0.);
|
|
||||||
|
|
||||||
MouseEventHandler::new::<ChannelCall, _>(channel.id as usize, cx, |state, cx| {
|
|
||||||
let participants = self.channel_store.read(cx).channel_participants(channel_id);
|
|
||||||
let extra_count = participants.len().saturating_sub(FACEPILE_LIMIT);
|
|
||||||
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(
|
|
||||||
FacePile::new(theme.face_overlap)
|
|
||||||
.with_children(
|
|
||||||
participants
|
|
||||||
.iter()
|
|
||||||
.filter_map(|user| {
|
|
||||||
Some(
|
|
||||||
Image::from_data(user.avatar.clone()?)
|
|
||||||
.with_style(theme.channel_avatar),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.take(FACEPILE_LIMIT),
|
|
||||||
)
|
|
||||||
.with_children((extra_count > 0).then(|| {
|
|
||||||
Label::new(
|
|
||||||
format!("+{}", extra_count),
|
|
||||||
theme.extra_participant_label.text.clone(),
|
|
||||||
)
|
|
||||||
.contained()
|
|
||||||
.with_style(theme.extra_participant_label.container)
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.align_children_center()
|
|
||||||
.constrained()
|
|
||||||
.with_height(theme.row_height)
|
|
||||||
.aligned()
|
|
||||||
.left()
|
|
||||||
.contained()
|
|
||||||
.with_style(*theme.channel_row.style_for(is_selected || is_active, state))
|
|
||||||
.with_padding_left(
|
|
||||||
theme.channel_row.default_style().padding.left
|
|
||||||
+ theme.channel_indent * (depth + 1) as f32,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
|
||||||
this.join_channel_call(channel_id, cx);
|
|
||||||
})
|
|
||||||
.on_click(MouseButton::Right, move |e, this, cx| {
|
|
||||||
this.deploy_channel_context_menu(Some(e.position), channel_id, cx);
|
|
||||||
})
|
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
|
||||||
.into_any()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_channel_notes(
|
fn render_channel_notes(
|
||||||
&self,
|
&self,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
|
@ -1775,7 +1703,7 @@ impl CollabPanel {
|
||||||
.with_padding_left(theme.channel_row.default_style().padding.left)
|
.with_padding_left(theme.channel_row.default_style().padding.left)
|
||||||
})
|
})
|
||||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
.on_click(MouseButton::Left, move |_, this, cx| {
|
||||||
this.open_channel_buffer(&OpenChannelBuffer { channel_id }, cx);
|
this.open_channel_notes(&OpenChannelNotes { channel_id }, cx);
|
||||||
})
|
})
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
.into_any()
|
.into_any()
|
||||||
|
@ -1987,7 +1915,7 @@ impl CollabPanel {
|
||||||
|
|
||||||
let mut items = vec![
|
let mut items = vec![
|
||||||
ContextMenuItem::action(expand_action_name, ToggleCollapse { channel_id }),
|
ContextMenuItem::action(expand_action_name, ToggleCollapse { channel_id }),
|
||||||
ContextMenuItem::action("Open Notes", OpenChannelBuffer { channel_id }),
|
ContextMenuItem::action("Open Notes", OpenChannelNotes { channel_id }),
|
||||||
];
|
];
|
||||||
|
|
||||||
if self.channel_store.read(cx).is_user_admin(channel_id) {
|
if self.channel_store.read(cx).is_user_admin(channel_id) {
|
||||||
|
@ -2114,9 +2042,6 @@ impl CollabPanel {
|
||||||
ListEntry::Channel { channel, .. } => {
|
ListEntry::Channel { channel, .. } => {
|
||||||
self.join_channel_chat(channel.id, cx);
|
self.join_channel_chat(channel.id, cx);
|
||||||
}
|
}
|
||||||
ListEntry::ChannelCall { channel, .. } => {
|
|
||||||
self.join_channel_call(channel.id, cx);
|
|
||||||
}
|
|
||||||
ListEntry::ContactPlaceholder => self.toggle_contact_finder(cx),
|
ListEntry::ContactPlaceholder => self.toggle_contact_finder(cx),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -2325,7 +2250,7 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_channel_buffer(&mut self, action: &OpenChannelBuffer, cx: &mut ViewContext<Self>) {
|
fn open_channel_notes(&mut self, action: &OpenChannelNotes, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(workspace) = self.workspace.upgrade(cx) {
|
if let Some(workspace) = self.workspace.upgrade(cx) {
|
||||||
let pane = workspace.read(cx).active_pane().clone();
|
let pane = workspace.read(cx).active_pane().clone();
|
||||||
let channel_id = action.channel_id;
|
let channel_id = action.channel_id;
|
||||||
|
@ -2510,7 +2435,9 @@ impl CollabPanel {
|
||||||
.detach_and_log_err(cx);
|
.detach_and_log_err(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join_channel_chat(&self, channel_id: u64, cx: &mut ViewContext<Self>) {
|
fn join_channel_chat(&mut self, channel_id: u64, cx: &mut ViewContext<Self>) {
|
||||||
|
self.open_channel_notes(&OpenChannelNotes { channel_id }, cx);
|
||||||
|
|
||||||
if let Some(workspace) = self.workspace.upgrade(cx) {
|
if let Some(workspace) = self.workspace.upgrade(cx) {
|
||||||
cx.app_context().defer(move |cx| {
|
cx.app_context().defer(move |cx| {
|
||||||
workspace.update(cx, |workspace, cx| {
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
@ -2757,18 +2684,6 @@ impl PartialEq for ListEntry {
|
||||||
return channel_1.id == channel_2.id && depth_1 == depth_2;
|
return channel_1.id == channel_2.id && depth_1 == depth_2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListEntry::ChannelCall {
|
|
||||||
channel: channel_1,
|
|
||||||
depth: depth_1,
|
|
||||||
} => {
|
|
||||||
if let ListEntry::ChannelCall {
|
|
||||||
channel: channel_2,
|
|
||||||
depth: depth_2,
|
|
||||||
} = other
|
|
||||||
{
|
|
||||||
return channel_1.id == channel_2.id && depth_1 == depth_2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ListEntry::ChannelNotes { channel_id } => {
|
ListEntry::ChannelNotes { channel_id } => {
|
||||||
if let ListEntry::ChannelNotes {
|
if let ListEntry::ChannelNotes {
|
||||||
channel_id: other_id,
|
channel_id: other_id,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue