From a4bfd0147dd30aa12003beaa9f0938e3540196bd Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 Dec 2023 09:48:45 -0800 Subject: [PATCH 1/4] Render channel invites in collab panel, fix unused warnings --- crates/collab_ui2/src/collab_panel.rs | 841 +++--------------- .../src/collab_panel/channel_modal.rs | 1 + .../src/collab_panel/contact_finder.rs | 1 + 3 files changed, 144 insertions(+), 699 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index cbae0763043dab56ba6cc22ef74d359c5eed72d8..c58d7c47bc29ddca60fe562a80c7b591f246fca2 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -1,4 +1,3 @@ -#![allow(unused)] mod channel_modal; mod contact_finder; @@ -317,18 +316,10 @@ pub struct CollabPanel { subscriptions: Vec, collapsed_sections: Vec
, collapsed_channels: Vec, - drag_target_channel: ChannelDragTarget, workspace: WeakView, // context_menu_on_selected: bool, } -#[derive(PartialEq, Eq)] -enum ChannelDragTarget { - None, - Root, - Channel(ChannelId), -} - #[derive(Serialize, Deserialize)] struct SerializedCollabPanel { width: Option, @@ -373,7 +364,7 @@ enum ListEntry { }, IncomingRequest(Arc), OutgoingRequest(Arc), - // ChannelInvite(Arc), + ChannelInvite(Arc), Channel { channel: Arc, depth: usize, @@ -472,8 +463,6 @@ impl CollabPanel { collapsed_channels: Vec::default(), workspace: workspace.weak_handle(), client: workspace.app_state().client.clone(), - // context_menu_on_selected: true, - drag_target_channel: ChannelDragTarget::None, }; this.update_entries(false, cx); @@ -529,9 +518,6 @@ impl CollabPanel { }) } - fn contacts(&self, cx: &AppContext) -> Option>> { - Some(self.user_store.read(cx).contacts().to_owned()) - } pub async fn load( workspace: WeakView, mut cx: AsyncWindowContext, @@ -808,37 +794,37 @@ impl CollabPanel { } } - // let channel_invites = channel_store.channel_invitations(); - // if !channel_invites.is_empty() { - // self.match_candidates.clear(); - // self.match_candidates - // .extend(channel_invites.iter().enumerate().map(|(ix, channel)| { - // StringMatchCandidate { - // id: ix, - // string: channel.name.clone(), - // char_bag: channel.name.chars().collect(), - // } - // })); - // let matches = executor.block(match_strings( - // &self.match_candidates, - // &query, - // true, - // usize::MAX, - // &Default::default(), - // executor.clone(), - // )); - // request_entries.extend(matches.iter().map(|mat| { - // ListEntry::ChannelInvite(channel_invites[mat.candidate_id].clone()) - // })); - - // if !request_entries.is_empty() { - // self.entries - // .push(ListEntry::Header(Section::ChannelInvites)); - // if !self.collapsed_sections.contains(&Section::ChannelInvites) { - // self.entries.append(&mut request_entries); - // } - // } - // } + let channel_invites = channel_store.channel_invitations(); + if !channel_invites.is_empty() { + self.match_candidates.clear(); + self.match_candidates + .extend(channel_invites.iter().enumerate().map(|(ix, channel)| { + StringMatchCandidate { + id: ix, + string: channel.name.clone().into(), + char_bag: channel.name.chars().collect(), + } + })); + let matches = executor.block(match_strings( + &self.match_candidates, + &query, + true, + usize::MAX, + &Default::default(), + executor.clone(), + )); + request_entries.extend(matches.iter().map(|mat| { + ListEntry::ChannelInvite(channel_invites[mat.candidate_id].clone()) + })); + + if !request_entries.is_empty() { + self.entries + .push(ListEntry::Header(Section::ChannelInvites)); + if !self.collapsed_sections.contains(&Section::ChannelInvites) { + self.entries.append(&mut request_entries); + } + } + } } self.entries.push(ListEntry::Header(Section::Contacts)); @@ -1049,9 +1035,7 @@ impl CollabPanel { } else if is_current_user { IconButton::new("leave-call", Icon::Exit) .style(ButtonStyle::Subtle) - .on_click(cx.listener(move |this, _, cx| { - Self::leave_call(cx); - })) + .on_click(move |_, cx| Self::leave_call(cx)) .tooltip(|cx| Tooltip::text("Leave Call", cx)) .into_any_element() } else { @@ -1061,7 +1045,8 @@ impl CollabPanel { this.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx)) .on_click(cx.listener(move |this, _, cx| { this.workspace - .update(cx, |workspace, cx| workspace.follow(peer_id, cx)); + .update(cx, |workspace, cx| workspace.follow(peer_id, cx)) + .ok(); })) }) } @@ -1073,7 +1058,7 @@ impl CollabPanel { host_user_id: u64, // is_current: bool, is_last: bool, - // is_selected: bool, + is_selected: bool, // theme: &theme::Theme, cx: &mut ViewContext, ) -> impl IntoElement { @@ -1084,15 +1069,16 @@ impl CollabPanel { } .into(); - let theme = cx.theme(); - ListItem::new(project_id as usize) + .selected(is_selected) .on_click(cx.listener(move |this, _, cx| { - this.workspace.update(cx, |workspace, cx| { - let app_state = workspace.app_state().clone(); - workspace::join_remote_project(project_id, host_user_id, app_state, cx) - .detach_and_log_err(cx); - }); + this.workspace + .update(cx, |workspace, cx| { + let app_state = workspace.app_state().clone(); + workspace::join_remote_project(project_id, host_user_id, app_state, cx) + .detach_and_log_err(cx); + }) + .ok(); })) .start_slot( h_stack() @@ -1102,95 +1088,19 @@ impl CollabPanel { ) .child(Label::new(project_name.clone())) .tooltip(move |cx| Tooltip::text(format!("Open {}", project_name), cx)) - - // enum JoinProject {} - // enum JoinProjectTooltip {} - - // let collab_theme = &theme.collab_panel; - // let host_avatar_width = collab_theme - // .contact_avatar - // .width - // .or(collab_theme.contact_avatar.height) - // .unwrap_or(0.); - // let tree_branch = collab_theme.tree_branch; - - // let content = - // MouseEventHandler::new::(project_id as usize, cx, |mouse_state, cx| { - // let tree_branch = *tree_branch.in_state(is_selected).style_for(mouse_state); - // let row = if is_current { - // collab_theme - // .project_row - // .in_state(true) - // .style_for(&mut Default::default()) - // } else { - // collab_theme - // .project_row - // .in_state(is_selected) - // .style_for(mouse_state) - // }; - - // Flex::row() - // .with_child(render_tree_branch( - // tree_branch, - // &row.name.text, - // is_last, - // vec2f(host_avatar_width, collab_theme.row_height), - // cx.font_cache(), - // )) - // .with_child( - // Svg::new("icons/file_icons/folder.svg") - // .with_color(collab_theme.channel_hash.color) - // .constrained() - // .with_width(collab_theme.channel_hash.width) - // .aligned() - // .left(), - // ) - // .with_child( - // Label::new(project_name.clone(), row.name.text.clone()) - // .aligned() - // .left() - // .contained() - // .with_style(row.name.container) - // .flex(1., false), - // ) - // .constrained() - // .with_height(collab_theme.row_height) - // .contained() - // .with_style(row.container) - // }); - - // if is_current { - // return content.into_any(); - // } - - // content - // .with_cursor_style(CursorStyle::PointingHand) - // .on_click(MouseButton::Left, move |_, this, cx| { - // if let Some(workspace) = this.workspace.upgrade(cx) { - // let app_state = workspace.read(cx).app_state().clone(); - // workspace::join_remote_project(project_id, host_user_id, app_state, cx) - // .detach_and_log_err(cx); - // } - // }) - // .with_tooltip::( - // project_id as usize, - // format!("Open {}", project_name), - // None, - // theme.tooltip.clone(), - // cx, - // ) - // .into_any() } fn render_participant_screen( &self, peer_id: Option, is_last: bool, + is_selected: bool, cx: &mut ViewContext, ) -> impl IntoElement { let id = peer_id.map_or(usize::MAX, |id| id.as_u64() as usize); ListItem::new(("screen", id)) + .selected(is_selected) .start_slot( h_stack() .gap_1() @@ -1200,9 +1110,11 @@ impl CollabPanel { .child(Label::new("Screen")) .when_some(peer_id, |this, _| { this.on_click(cx.listener(move |this, _, cx| { - this.workspace.update(cx, |workspace, cx| { - workspace.open_shared_screen(peer_id.unwrap(), cx) - }); + this.workspace + .update(cx, |workspace, cx| { + workspace.open_shared_screen(peer_id.unwrap(), cx) + }) + .ok(); })) .tooltip(move |cx| Tooltip::text(format!("Open shared screen"), cx)) }) @@ -1291,86 +1203,6 @@ impl CollabPanel { .tooltip(move |cx| Tooltip::text("Open Chat", cx)) } - // fn render_channel_invite( - // channel: Arc, - // channel_store: ModelHandle, - // theme: &theme::CollabPanel, - // is_selected: bool, - // cx: &mut ViewContext, - // ) -> AnyElement { - // enum Decline {} - // enum Accept {} - - // let channel_id = channel.id; - // let is_invite_pending = channel_store - // .read(cx) - // .has_pending_channel_invite_response(&channel); - // let button_spacing = theme.contact_button_spacing; - - // Flex::row() - // .with_child( - // Svg::new("icons/hash.svg") - // .with_color(theme.channel_hash.color) - // .constrained() - // .with_width(theme.channel_hash.width) - // .aligned() - // .left(), - // ) - // .with_child( - // Label::new(channel.name.clone(), theme.contact_username.text.clone()) - // .contained() - // .with_style(theme.contact_username.container) - // .aligned() - // .left() - // .flex(1., true), - // ) - // .with_child( - // MouseEventHandler::new::(channel.id as usize, cx, |mouse_state, _| { - // let button_style = if is_invite_pending { - // &theme.disabled_button - // } else { - // theme.contact_button.style_for(mouse_state) - // }; - // render_icon_button(button_style, "icons/x.svg").aligned() - // }) - // .with_cursor_style(CursorStyle::PointingHand) - // .on_click(MouseButton::Left, move |_, this, cx| { - // this.respond_to_channel_invite(channel_id, false, cx); - // }) - // .contained() - // .with_margin_right(button_spacing), - // ) - // .with_child( - // MouseEventHandler::new::(channel.id as usize, cx, |mouse_state, _| { - // let button_style = if is_invite_pending { - // &theme.disabled_button - // } else { - // theme.contact_button.style_for(mouse_state) - // }; - // render_icon_button(button_style, "icons/check.svg") - // .aligned() - // .flex_float() - // }) - // .with_cursor_style(CursorStyle::PointingHand) - // .on_click(MouseButton::Left, move |_, this, cx| { - // this.respond_to_channel_invite(channel_id, true, cx); - // }), - // ) - // .constrained() - // .with_height(theme.row_height) - // .contained() - // .with_style( - // *theme - // .contact_row - // .in_state(is_selected) - // .style_for(&mut Default::default()), - // ) - // .with_padding_left( - // theme.contact_row.default_style().padding.left + theme.channel_indent, - // ) - // .into_any() - // } - fn has_subchannels(&self, ix: usize) -> bool { self.entries.get(ix).map_or(false, |entry| { if let ListEntry::Channel { has_children, .. } = entry { @@ -1724,7 +1556,7 @@ impl CollabPanel { self.collapsed_channels.binary_search(&channel_id).is_ok() } - fn leave_call(cx: &mut ViewContext) { + fn leave_call(cx: &mut WindowContext) { ActiveCall::global(cx) .update(cx, |call, cx| call.hang_up(cx)) .detach_and_log_err(cx); @@ -1813,15 +1645,13 @@ impl CollabPanel { } } - fn start_move_channel(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn start_move_channel(&mut self, channel_id: ChannelId, _cx: &mut ViewContext) { self.channel_clipboard = Some(ChannelMoveClipboard { channel_id }); } - fn start_move_selected_channel(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + fn start_move_selected_channel(&mut self, _: &StartMoveChannel, cx: &mut ViewContext) { if let Some(channel) = self.selected_channel() { - self.channel_clipboard = Some(ChannelMoveClipboard { - channel_id: channel.id, - }) + self.start_move_channel(channel.id, cx); } } @@ -1900,10 +1730,6 @@ impl CollabPanel { .detach(); } - // fn remove_selected_channel(&mut self, action: &RemoveChannel, cx: &mut ViewContext) { - // self.remove_channel(action.channel_id, cx) - // } - fn remove_channel(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { let channel_store = self.channel_store.clone(); if let Some(channel) = channel_store.read(cx).channel_for_id(channel_id) { @@ -1911,9 +1737,7 @@ impl CollabPanel { "Are you sure you want to remove the channel \"{}\"?", channel.name ); - let mut answer = - cx.prompt(PromptLevel::Warning, &prompt_message, &["Remove", "Cancel"]); - let window = cx.window(); + let answer = cx.prompt(PromptLevel::Warning, &prompt_message, &["Remove", "Cancel"]); cx.spawn(|this, mut cx| async move { if answer.await? == 0 { channel_store @@ -1937,8 +1761,7 @@ impl CollabPanel { "Are you sure you want to remove \"{}\" from your contacts?", github_login ); - let mut answer = cx.prompt(PromptLevel::Warning, &prompt_message, &["Remove", "Cancel"]); - let window = cx.window(); + let answer = cx.prompt(PromptLevel::Warning, &prompt_message, &["Remove", "Cancel"]); cx.spawn(|_, mut cx| async move { if answer.await? == 0 { user_store @@ -1964,18 +1787,18 @@ impl CollabPanel { .detach_and_log_err(cx); } - // fn respond_to_channel_invite( - // &mut self, - // channel_id: u64, - // accept: bool, - // cx: &mut ViewContext, - // ) { - // self.channel_store - // .update(cx, |store, cx| { - // store.respond_to_channel_invite(channel_id, accept, cx) - // }) - // .detach(); - // } + fn respond_to_channel_invite( + &mut self, + channel_id: u64, + accept: bool, + cx: &mut ViewContext, + ) { + self.channel_store + .update(cx, |store, cx| { + store.respond_to_channel_invite(channel_id, accept, cx) + }) + .detach(); + } fn call(&mut self, recipient_user_id: u64, cx: &mut ViewContext) { ActiveCall::global(cx) @@ -2096,6 +1919,9 @@ impl CollabPanel { ListEntry::ChannelEditor { depth } => { self.render_channel_editor(*depth, cx).into_any_element() } + ListEntry::ChannelInvite(channel) => self + .render_channel_invite(channel, is_selected, cx) + .into_any_element(), ListEntry::CallParticipant { user, peer_id, @@ -2114,11 +1940,12 @@ impl CollabPanel { &worktree_root_names, *host_user_id, *is_last, + is_selected, cx, ) .into_any_element(), ListEntry::ParticipantScreen { peer_id, is_last } => self - .render_participant_screen(*peer_id, *is_last, cx) + .render_participant_screen(*peer_id, *is_last, is_selected, cx) .into_any_element(), ListEntry::ChannelNotes { channel_id } => self .render_channel_notes(*channel_id, cx) @@ -2233,7 +2060,7 @@ impl CollabPanel { ListHeader::new(text) .when(can_collapse, |header| { header.toggle(Some(!is_collapsed)).on_toggle(cx.listener( - move |this, event, cx| { + move |this, _, cx| { this.toggle_section_expanded(section, cx); }, )) @@ -2265,8 +2092,9 @@ impl CollabPanel { let busy = contact.busy || calling; let user_id = contact.user.id; let github_login = SharedString::from(contact.user.github_login.clone()); - let mut item = + let item = ListItem::new(github_login.clone()) + .selected(is_selected) .on_click(cx.listener(move |this, _, cx| this.call(user_id, cx))) .child( h_stack() @@ -2330,8 +2158,8 @@ impl CollabPanel { ) -> impl IntoElement { let github_login = SharedString::from(user.github_login.clone()); let user_id = user.id; - let is_contact_request_pending = self.user_store.read(cx).is_contact_request_pending(&user); - let color = if is_contact_request_pending { + let is_response_pending = self.user_store.read(cx).is_contact_request_pending(&user); + let color = if is_response_pending { Color::Muted } else { Color::Default @@ -2363,6 +2191,7 @@ impl CollabPanel { }; ListItem::new(github_login.clone()) + .selected(is_selected) .child( h_stack() .w_full() @@ -2373,6 +2202,54 @@ impl CollabPanel { .start_slot(Avatar::new(user.avatar_uri.clone())) } + fn render_channel_invite( + &self, + channel: &Arc, + is_selected: bool, + cx: &mut ViewContext, + ) -> impl IntoElement { + let channel_id = channel.id; + let response_is_pending = self + .channel_store + .read(cx) + .has_pending_channel_invite_response(&channel); + let color = if response_is_pending { + Color::Muted + } else { + Color::Default + }; + + let controls = [ + IconButton::new("remove_contact", Icon::Close) + .on_click(cx.listener(move |this, _, cx| { + this.respond_to_channel_invite(channel_id, false, cx); + })) + .icon_color(color) + .tooltip(|cx| Tooltip::text("Decline invite", cx)), + IconButton::new("remove_contact", Icon::Check) + .on_click(cx.listener(move |this, _, cx| { + this.respond_to_contact_request(channel_id, true, cx); + })) + .icon_color(color) + .tooltip(|cx| Tooltip::text("Accept invite", cx)), + ]; + + ListItem::new(("channel-invite", channel.id as usize)) + .selected(is_selected) + .child( + h_stack() + .w_full() + .justify_between() + .child(Label::new(channel.name.clone())) + .child(h_stack().children(controls)), + ) + .start_slot( + IconElement::new(Icon::Hash) + .size(IconSize::Small) + .color(Color::Muted), + ) + } + fn render_contact_placeholder( &self, is_selected: bool, @@ -2411,7 +2288,6 @@ impl CollabPanel { .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()); @@ -2423,14 +2299,10 @@ impl CollabPanel { let face_pile = if !participants.is_empty() { let extra_count = participants.len().saturating_sub(FACEPILE_LIMIT); - let user = &participants[0]; - let result = FacePile { faces: participants .iter() - .filter_map(|user| { - Some(Avatar::new(user.avatar_uri.clone()).into_any_element()) - }) + .map(|user| Avatar::new(user.avatar_uri.clone()).into_any_element()) .take(FACEPILE_LIMIT) .chain(if extra_count > 0 { // todo!() @nate - this label looks wrong. @@ -2454,7 +2326,7 @@ impl CollabPanel { .flex() .w_full() .on_drag(channel.clone(), move |channel, cx| { - cx.build_view(|cx| DraggedChannelView { + cx.build_view(|_| DraggedChannelView { channel: channel.clone(), width, }) @@ -2480,12 +2352,10 @@ impl CollabPanel { }), ) .on_click(cx.listener(move |this, _, cx| { - if this.drag_target_channel == ChannelDragTarget::None { - if is_active { - this.open_channel_notes(channel_id, cx) - } else { - this.join_channel(channel_id, cx) - } + if is_active { + this.open_channel_notes(channel_id, cx) + } else { + this.join_channel(channel_id, cx) } })) .on_secondary_mouse_down(cx.listener( @@ -2537,316 +2407,9 @@ impl CollabPanel { ), ) .tooltip(|cx| Tooltip::text("Join channel", cx)) + } - // let channel_id = channel.id; - // let collab_theme = &theme.collab_panel; - // 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()); - - // enum ChannelCall {} - // enum ChannelNote {} - // enum NotesTooltip {} - // enum ChatTooltip {} - // enum ChannelTooltip {} - - // let mut is_dragged_over = false; - // if cx - // .global::>() - // .currently_dragged::(cx.window()) - // .is_some() - // && self.drag_target_channel == ChannelDragTarget::Channel(channel_id) - // { - // is_dragged_over = true; - // } - - // let has_messages_notification = channel.unseen_message_id.is_some(); - - // MouseEventHandler::new::(ix, cx, |state, cx| { - // let row_hovered = state.hovered(); - - // let mut select_state = |interactive: &Interactive| { - // if state.clicked() == Some(MouseButton::Left) && interactive.clicked.is_some() { - // interactive.clicked.as_ref().unwrap().clone() - // } else if state.hovered() || other_selected { - // interactive - // .hovered - // .as_ref() - // .unwrap_or(&interactive.default) - // .clone() - // } else { - // interactive.default.clone() - // } - // }; - - // Flex::::row() - // .with_child( - // Svg::new(if is_public { - // "icons/public.svg" - // } else { - // "icons/hash.svg" - // }) - // .with_color(collab_theme.channel_hash.color) - // .constrained() - // .with_width(collab_theme.channel_hash.width) - // .aligned() - // .left(), - // ) - // .with_child({ - // let style = collab_theme.channel_name.inactive_state(); - // Flex::row() - // .with_child( - // Label::new(channel.name.clone(), style.text.clone()) - // .contained() - // .with_style(style.container) - // .aligned() - // .left() - // .with_tooltip::( - // ix, - // "Join channel", - // None, - // theme.tooltip.clone(), - // cx, - // ), - // ) - // .with_children({ - // let participants = - // self.channel_store.read(cx).channel_participants(channel_id); - - // if !participants.is_empty() { - // let extra_count = participants.len().saturating_sub(FACEPILE_LIMIT); - - // let result = FacePile::new(collab_theme.face_overlap) - // .with_children( - // participants - // .iter() - // .filter_map(|user| { - // Some( - // Image::from_data(user.avatar.clone()?) - // .with_style(collab_theme.channel_avatar), - // ) - // }) - // .take(FACEPILE_LIMIT), - // ) - // .with_children((extra_count > 0).then(|| { - // Label::new( - // format!("+{}", extra_count), - // collab_theme.extra_participant_label.text.clone(), - // ) - // .contained() - // .with_style(collab_theme.extra_participant_label.container) - // })); - - // Some(result) - // } else { - // None - // } - // }) - // .with_spacing(8.) - // .align_children_center() - // .flex(1., true) - // }) - // .with_child( - // MouseEventHandler::new::(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().into_any() - // } - // }) - // .on_click(MouseButton::Left, move |_, this, cx| { - // this.join_channel_chat(&JoinChannelChat { channel_id }, cx); - // }) - // .with_tooltip::( - // ix, - // "Open channel chat", - // None, - // theme.tooltip.clone(), - // cx, - // ) - // .contained() - // .with_margin_right(4.), - // ) - // .with_child( - // MouseEventHandler::new::(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() { - // collab_theme.channel_note_active_color - // } else { - // collab_theme.channel_hash.color - // }) - // .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::( - // ix as usize, - // "Open channel notes", - // None, - // theme.tooltip.clone(), - // cx, - // ) - // .into_any() - // } 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| { - // this.open_channel_notes(&OpenChannelNotes { channel_id }, cx); - // }), - // ) - // .align_children_center() - // .styleable_component() - // .disclosable( - // disclosed, - // Box::new(ToggleCollapse { - // location: channel.id.clone(), - // }), - // ) - // .with_id(ix) - // .with_style(collab_theme.disclosure.clone()) - // .element() - // .constrained() - // .with_height(collab_theme.row_height) - // .contained() - // .with_style(select_state( - // collab_theme - // .channel_row - // .in_state(is_selected || is_active || is_dragged_over), - // )) - // .with_padding_left( - // collab_theme.channel_row.default_style().padding.left - // + collab_theme.channel_indent * depth as f32, - // ) - // }) - // .on_click(MouseButton::Left, move |_, this, cx| { - // if this. - // drag_target_channel == ChannelDragTarget::None { - // if is_active { - // this.open_channel_notes(&OpenChannelNotes { channel_id }, cx) - // } else { - // this.join_channel(channel_id, cx) - // } - // } - // }) - // .on_click(MouseButton::Right, { - // let channel = channel.clone(); - // move |e, this, cx| { - // this.deploy_channel_context_menu(Some(e.position), &channel, ix, cx); - // } - // }) - // .on_up(MouseButton::Left, move |_, this, cx| { - // if let Some((_, dragged_channel)) = cx - // .global::>() - // .currently_dragged::(cx.window()) - // { - // this.channel_store - // .update(cx, |channel_store, cx| { - // channel_store.move_channel(dragged_channel.id, Some(channel_id), cx) - // }) - // .detach_and_log_err(cx) - // } - // }) - // .on_move({ - // let channel = channel.clone(); - // move |_, this, cx| { - // if let Some((_, dragged_channel)) = cx - // .global::>() - // .currently_dragged::(cx.window()) - // { - // if channel.id != dragged_channel.id { - // this.drag_target_channel = ChannelDragTarget::Channel(channel.id); - // } - // cx.notify() - // } - // } - // }) - // .as_draggable::<_, Channel>( - // channel.clone(), - // move |_, channel, cx: &mut ViewContext| { - // let theme = &theme::current(cx).collab_panel; - - // Flex::::row() - // .with_child( - // Svg::new("icons/hash.svg") - // .with_color(theme.channel_hash.color) - // .constrained() - // .with_width(theme.channel_hash.width) - // .aligned() - // .left(), - // ) - // .with_child( - // Label::new(channel.name.clone(), theme.channel_name.text.clone()) - // .contained() - // .with_style(theme.channel_name.container) - // .aligned() - // .left(), - // ) - // .align_children_center() - // .contained() - // .with_background_color( - // theme - // .container - // .background_color - // .unwrap_or(gpui::color::Color::transparent_black()), - // ) - // .contained() - // .with_padding_left( - // theme.channel_row.default_style().padding.left - // + theme.channel_indent * depth as f32, - // ) - // .into_any() - // }, - // ) - // .with_cursor_style(CursorStyle::PointingHand) - // .into_any() - } - - fn render_channel_editor(&self, depth: usize, cx: &mut ViewContext) -> impl IntoElement { + fn render_channel_editor(&self, depth: usize, _cx: &mut ViewContext) -> impl IntoElement { let item = ListItem::new("channel-editor") .inset(false) .indent_level(depth) @@ -2916,20 +2479,12 @@ impl Render for CollabPanel { .on_action(cx.listener(CollabPanel::select_prev)) .on_action(cx.listener(CollabPanel::confirm)) .on_action(cx.listener(CollabPanel::insert_space)) - // .on_action(cx.listener(CollabPanel::remove)) .on_action(cx.listener(CollabPanel::remove_selected_channel)) .on_action(cx.listener(CollabPanel::show_inline_context_menu)) - // .on_action(cx.listener(CollabPanel::new_subchannel)) - // .on_action(cx.listener(CollabPanel::invite_members)) - // .on_action(cx.listener(CollabPanel::manage_members)) .on_action(cx.listener(CollabPanel::rename_selected_channel)) - // .on_action(cx.listener(CollabPanel::rename_channel)) - // .on_action(cx.listener(CollabPanel::toggle_channel_collapsed_action)) .on_action(cx.listener(CollabPanel::collapse_selected_channel)) .on_action(cx.listener(CollabPanel::expand_selected_channel)) - // .on_action(cx.listener(CollabPanel::open_channel_notes)) - // .on_action(cx.listener(CollabPanel::join_channel_chat)) - // .on_action(cx.listener(CollabPanel::copy_channel_link)) + .on_action(cx.listener(CollabPanel::start_move_selected_channel)) .track_focus(&self.focus_handle) .size_full() .child(if self.user_store.read(cx).current_user().is_none() { @@ -2946,105 +2501,6 @@ impl Render for CollabPanel { } } -// impl View for CollabPanel { -// fn ui_name() -> &'static str { -// "CollabPanel" -// } - -// fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { -// if !self.has_focus { -// self.has_focus = true; -// if !self.context_menu.is_focused(cx) { -// if let Some(editing_state) = &self.channel_editing_state { -// if editing_state.pending_name().is_none() { -// cx.focus(&self.channel_name_editor); -// } else { -// cx.focus(&self.filter_editor); -// } -// } else { -// cx.focus(&self.filter_editor); -// } -// } -// cx.emit(Event::Focus); -// } -// } - -// fn focus_out(&mut self, _: gpui::AnyViewHandle, _: &mut ViewContext) { -// self.has_focus = false; -// } - -// fn render(&mut self, cx: &mut gpui::ViewContext<'_, '_, Self>) -> gpui::AnyElement { -// let theme = &theme::current(cx).collab_panel; - -// if self.user_store.read(cx).current_user().is_none() { -// enum LogInButton {} - -// return Flex::column() -// .with_child( -// MouseEventHandler::new::(0, cx, |state, _| { -// let button = theme.log_in_button.style_for(state); -// Label::new("Sign in to collaborate", button.text.clone()) -// .aligned() -// .left() -// .contained() -// .with_style(button.container) -// }) -// .on_click(MouseButton::Left, |_, this, cx| { -// let client = this.client.clone(); -// cx.spawn(|_, cx| async move { -// client.authenticate_and_connect(true, &cx).await.log_err(); -// }) -// .detach(); -// }) -// .with_cursor_style(CursorStyle::PointingHand), -// ) -// .contained() -// .with_style(theme.container) -// .into_any(); -// } - -// enum PanelFocus {} -// MouseEventHandler::new::(0, cx, |_, cx| { -// Stack::new() -// .with_child( -// Flex::column() -// .with_child( -// Flex::row().with_child( -// ChildView::new(&self.filter_editor, cx) -// .contained() -// .with_style(theme.user_query_editor.container) -// .flex(1.0, true), -// ), -// ) -// .with_child(List::new(self.list_state.clone()).flex(1., true).into_any()) -// .contained() -// .with_style(theme.container) -// .into_any(), -// ) -// .with_children( -// (!self.context_menu_on_selected) -// .then(|| ChildView::new(&self.context_menu, cx)), -// ) -// .into_any() -// }) -// .on_click(MouseButton::Left, |_, _, cx| cx.focus_self()) -// .into_any_named("collab panel") -// } - -// fn update_keymap_context( -// &self, -// keymap: &mut gpui::keymap_matcher::KeymapContext, -// _: &AppContext, -// ) { -// Self::reset_to_default_keymap_context(keymap); -// if self.channel_editing_state.is_some() { -// keymap.add_identifier("editing"); -// } else { -// keymap.add_identifier("not_editing"); -// } -// } -// } - impl EventEmitter for CollabPanel {} impl Panel for CollabPanel { @@ -3159,11 +2615,11 @@ impl PartialEq for ListEntry { return channel_id == other_id; } } - // ListEntry::ChannelInvite(channel_1) => { - // if let ListEntry::ChannelInvite(channel_2) = other { - // return channel_1.id == channel_2.id; - // } - // } + ListEntry::ChannelInvite(channel_1) => { + if let ListEntry::ChannelInvite(channel_2) = other { + return channel_1.id == channel_2.id; + } + } ListEntry::IncomingRequest(user_1) => { if let ListEntry::IncomingRequest(user_2) = other { return user_1.id == user_2.id; @@ -3199,19 +2655,6 @@ impl PartialEq for ListEntry { } } -// fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element { -// Svg::new(svg_path) -// .with_color(style.color) -// .constrained() -// .with_width(style.icon_width) -// .aligned() -// .constrained() -// .with_width(style.button_width) -// .with_height(style.button_width) -// .contained() -// .with_style(style.container) -// } - struct DraggedChannelView { channel: Channel, width: Pixels, diff --git a/crates/collab_ui2/src/collab_panel/channel_modal.rs b/crates/collab_ui2/src/collab_panel/channel_modal.rs index 8636dcafe467d339986bf03ff0dea06382e20782..d903ecb086df8969e087e67b2d53b3a780d01236 100644 --- a/crates/collab_ui2/src/collab_panel/channel_modal.rs +++ b/crates/collab_ui2/src/collab_panel/channel_modal.rs @@ -1,3 +1,4 @@ +#![allow(unused)] use channel::{ChannelId, ChannelMembership, ChannelStore}; use client::{ proto::{self, ChannelRole, ChannelVisibility}, diff --git a/crates/collab_ui2/src/collab_panel/contact_finder.rs b/crates/collab_ui2/src/collab_panel/contact_finder.rs index ff7e02a909af3e9698d5126f5d0bd5c558e4685c..208727efd27132debb9f883af7c172154d2461f1 100644 --- a/crates/collab_ui2/src/collab_panel/contact_finder.rs +++ b/crates/collab_ui2/src/collab_panel/contact_finder.rs @@ -1,3 +1,4 @@ +#![allow(unused)] use client::{ContactRequestStatus, User, UserStore}; use gpui::{ div, img, svg, AnyElement, AppContext, DismissEvent, Div, Entity, EventEmitter, FocusHandle, From 80b6922de70b1b72d12030bef6ba981f2b439219 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 Dec 2023 10:15:00 -0800 Subject: [PATCH 2/4] wip --- .../src/collab_panel/channel_modal.rs | 213 +++++------------- 1 file changed, 51 insertions(+), 162 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel/channel_modal.rs b/crates/collab_ui2/src/collab_panel/channel_modal.rs index d903ecb086df8969e087e67b2d53b3a780d01236..0b407f0647cd47662f953aaec789fcbd44475bb7 100644 --- a/crates/collab_ui2/src/collab_panel/channel_modal.rs +++ b/crates/collab_ui2/src/collab_panel/channel_modal.rs @@ -1,4 +1,3 @@ -#![allow(unused)] use channel::{ChannelId, ChannelMembership, ChannelStore}; use client::{ proto::{self, ChannelRole, ChannelVisibility}, @@ -12,7 +11,7 @@ use gpui::{ }; use picker::{Picker, PickerDelegate}; use std::sync::Arc; -use ui::prelude::*; +use ui::{prelude::*, Checkbox}; use util::TryFutureExt; use workspace::ModalView; @@ -157,167 +156,57 @@ impl Render for ChannelModal { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - v_stack().w(rems(34.)).child(self.picker.clone()) - // let theme = &theme::current(cx).collab_panel.tabbed_modal; - - // let mode = self.picker.read(cx).delegate().mode; - // let Some(channel) = self.channel_store.read(cx).channel_for_id(self.channel_id) else { - // return Empty::new().into_any(); - // }; - - // enum InviteMembers {} - // enum ManageMembers {} - - // fn render_mode_button( - // mode: Mode, - // text: &'static str, - // current_mode: Mode, - // theme: &theme::TabbedModal, - // cx: &mut ViewContext, - // ) -> AnyElement { - // let active = mode == current_mode; - // MouseEventHandler::new::(0, cx, move |state, _| { - // let contained_text = theme.tab_button.style_for(active, state); - // Label::new(text, contained_text.text.clone()) - // .contained() - // .with_style(contained_text.container.clone()) - // }) - // .on_click(MouseButton::Left, move |_, this, cx| { - // if !active { - // this.set_mode(mode, cx); - // } - // }) - // .with_cursor_style(CursorStyle::PointingHand) - // .into_any() - // } - - // fn render_visibility( - // channel_id: ChannelId, - // visibility: ChannelVisibility, - // theme: &theme::TabbedModal, - // cx: &mut ViewContext, - // ) -> AnyElement { - // enum TogglePublic {} - - // if visibility == ChannelVisibility::Members { - // return Flex::row() - // .with_child( - // MouseEventHandler::new::(0, cx, move |state, _| { - // let style = theme.visibility_toggle.style_for(state); - // Label::new(format!("{}", "Public access: OFF"), style.text.clone()) - // .contained() - // .with_style(style.container.clone()) - // }) - // .on_click(MouseButton::Left, move |_, this, cx| { - // this.channel_store - // .update(cx, |channel_store, cx| { - // channel_store.set_channel_visibility( - // channel_id, - // ChannelVisibility::Public, - // cx, - // ) - // }) - // .detach_and_log_err(cx); - // }) - // .with_cursor_style(CursorStyle::PointingHand), - // ) - // .into_any(); - // } - - // Flex::row() - // .with_child( - // MouseEventHandler::new::(0, cx, move |state, _| { - // let style = theme.visibility_toggle.style_for(state); - // Label::new(format!("{}", "Public access: ON"), style.text.clone()) - // .contained() - // .with_style(style.container.clone()) - // }) - // .on_click(MouseButton::Left, move |_, this, cx| { - // this.channel_store - // .update(cx, |channel_store, cx| { - // channel_store.set_channel_visibility( - // channel_id, - // ChannelVisibility::Members, - // cx, - // ) - // }) - // .detach_and_log_err(cx); - // }) - // .with_cursor_style(CursorStyle::PointingHand), - // ) - // .with_spacing(14.0) - // .with_child( - // MouseEventHandler::new::(1, cx, move |state, _| { - // let style = theme.channel_link.style_for(state); - // Label::new(format!("{}", "copy link"), style.text.clone()) - // .contained() - // .with_style(style.container.clone()) - // }) - // .on_click(MouseButton::Left, move |_, this, cx| { - // if let Some(channel) = - // this.channel_store.read(cx).channel_for_id(channel_id) - // { - // let item = ClipboardItem::new(channel.link()); - // cx.write_to_clipboard(item); - // } - // }) - // .with_cursor_style(CursorStyle::PointingHand), - // ) - // .into_any() - // } - - // Flex::column() - // .with_child( - // Flex::column() - // .with_child( - // Label::new(format!("#{}", channel.name), theme.title.text.clone()) - // .contained() - // .with_style(theme.title.container.clone()), - // ) - // .with_child(render_visibility(channel.id, channel.visibility, theme, cx)) - // .with_child(Flex::row().with_children([ - // render_mode_button::( - // Mode::InviteMembers, - // "Invite members", - // mode, - // theme, - // cx, - // ), - // render_mode_button::( - // Mode::ManageMembers, - // "Manage members", - // mode, - // theme, - // cx, - // ), - // ])) - // .expanded() - // .contained() - // .with_style(theme.header), - // ) - // .with_child( - // ChildView::new(&self.picker, cx) - // .contained() - // .with_style(theme.body), - // ) - // .constrained() - // .with_max_height(theme.max_height) - // .with_max_width(theme.max_width) - // .contained() - // .with_style(theme.modal) - // .into_any() + let channel_store = self.channel_store.read(cx); + let Some(channel) = channel_store.channel_for_id(self.channel_id) else { + return div(); + }; + let mode = self.picker.read(cx).delegate.mode; + + v_stack() + .bg(cx.theme().colors().elevated_surface_background) + .w(rems(34.)) + .child(Label::new(channel.name.clone())) + .child( + div() + .w_full() + .flex_row() + .child(Checkbox::new( + "is-public", + if channel.visibility == ChannelVisibility::Public { + ui::Selection::Selected + } else { + ui::Selection::Unselected + }, + )) + .child(Label::new("Public")), + ) + .child( + div() + .w_full() + .flex_row() + .child( + Button::new("manage-members", "Manage Members") + .selected(mode == Mode::ManageMembers) + .on_click(cx.listener(|this, _, cx| { + this.picker.update(cx, |picker, _| { + picker.delegate.mode = Mode::ManageMembers + }); + cx.notify(); + })), + ) + .child( + Button::new("invite-members", "Invite Members") + .selected(mode == Mode::InviteMembers) + .on_click(cx.listener(|this, _, cx| { + this.picker.update(cx, |picker, _| { + picker.delegate.mode = Mode::InviteMembers + }); + cx.notify(); + })), + ), + ) + .child(self.picker.clone()) } - - // fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { - // self.has_focus = true; - // if cx.is_self_focused() { - // cx.focus(&self.picker) - // } - // } - - // fn focus_out(&mut self, _: gpui::AnyViewHandle, _: &mut ViewContext) { - // self.has_focus = false; - // } } #[derive(Copy, Clone, PartialEq)] From 1c3698ae20cdb2ec9aace81bb29d56f19e4f2888 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 Dec 2023 12:02:35 -0800 Subject: [PATCH 3/4] Implement channel modal Co-authored-by: Nathan --- crates/collab_ui2/src/collab_panel.rs | 10 +- .../src/collab_panel/channel_modal.rs | 432 ++++++++---------- crates/gpui2/src/window.rs | 7 - crates/picker2/src/picker2.rs | 2 +- crates/ui2/src/components/context_menu.rs | 5 +- crates/ui2/src/components/icon.rs | 2 + 6 files changed, 214 insertions(+), 244 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index c58d7c47bc29ddca60fe562a80c7b591f246fca2..3df8f06d3b328f287086eef1e048274a8008ca71 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -2167,13 +2167,13 @@ impl CollabPanel { let controls = if is_incoming { vec![ - IconButton::new("remove_contact", Icon::Close) + IconButton::new("decline-contact", Icon::Close) .on_click(cx.listener(move |this, _, cx| { this.respond_to_contact_request(user_id, false, cx); })) .icon_color(color) .tooltip(|cx| Tooltip::text("Decline invite", cx)), - IconButton::new("remove_contact", Icon::Check) + IconButton::new("accept-contact", Icon::Check) .on_click(cx.listener(move |this, _, cx| { this.respond_to_contact_request(user_id, true, cx); })) @@ -2220,15 +2220,15 @@ impl CollabPanel { }; let controls = [ - IconButton::new("remove_contact", Icon::Close) + IconButton::new("reject-invite", Icon::Close) .on_click(cx.listener(move |this, _, cx| { this.respond_to_channel_invite(channel_id, false, cx); })) .icon_color(color) .tooltip(|cx| Tooltip::text("Decline invite", cx)), - IconButton::new("remove_contact", Icon::Check) + IconButton::new("accept-invite", Icon::Check) .on_click(cx.listener(move |this, _, cx| { - this.respond_to_contact_request(channel_id, true, cx); + this.respond_to_channel_invite(channel_id, true, cx); })) .icon_color(color) .tooltip(|cx| Tooltip::text("Accept invite", cx)), diff --git a/crates/collab_ui2/src/collab_panel/channel_modal.rs b/crates/collab_ui2/src/collab_panel/channel_modal.rs index 0b407f0647cd47662f953aaec789fcbd44475bb7..f844c609cac074d6457613b81b654a8e0b1c5d3c 100644 --- a/crates/collab_ui2/src/collab_panel/channel_modal.rs +++ b/crates/collab_ui2/src/collab_panel/channel_modal.rs @@ -5,13 +5,13 @@ use client::{ }; use fuzzy::{match_strings, StringMatchCandidate}; use gpui::{ - actions, div, AppContext, ClipboardItem, DismissEvent, Div, Entity, EventEmitter, - FocusableView, Model, ParentElement, Render, Styled, Task, View, ViewContext, VisualContext, - WeakView, + actions, div, overlay, AppContext, ClipboardItem, DismissEvent, Div, EventEmitter, + FocusableView, Model, ParentElement, Render, Styled, Subscription, Task, View, ViewContext, + VisualContext, WeakView, }; use picker::{Picker, PickerDelegate}; use std::sync::Arc; -use ui::{prelude::*, Checkbox}; +use ui::{prelude::*, Avatar, Checkbox, ContextMenu, ListItem}; use util::TryFutureExt; use workspace::ModalView; @@ -25,19 +25,10 @@ actions!( ] ); -// pub fn init(cx: &mut AppContext) { -// Picker::::init(cx); -// cx.add_action(ChannelModal::toggle_mode); -// cx.add_action(ChannelModal::toggle_member_admin); -// cx.add_action(ChannelModal::remove_member); -// cx.add_action(ChannelModal::dismiss); -// } - pub struct ChannelModal { picker: View>, channel_store: Model, channel_id: ChannelId, - has_focus: bool, } impl ChannelModal { @@ -62,25 +53,19 @@ impl ChannelModal { channel_store: channel_store.clone(), channel_id, match_candidates: Vec::new(), + context_menu: None, members, mode, - // context_menu: cx.add_view(|cx| { - // let mut menu = ContextMenu::new(cx.view_id(), cx); - // menu.set_position_mode(OverlayPositionMode::Local); - // menu - // }), }, cx, ) + .modal(false) }); - let has_focus = picker.focus_handle(cx).contains_focused(cx); - Self { picker, channel_store, channel_id, - has_focus, } } @@ -126,15 +111,19 @@ impl ChannelModal { .detach(); } - fn toggle_member_admin(&mut self, _: &ToggleMemberAdmin, cx: &mut ViewContext) { - self.picker.update(cx, |picker, cx| { - picker.delegate.toggle_selected_member_admin(cx); - }) - } - - fn remove_member(&mut self, _: &RemoveMember, cx: &mut ViewContext) { - self.picker.update(cx, |picker, cx| { - picker.delegate.remove_selected_member(cx); + fn set_channel_visiblity(&mut self, selection: &Selection, cx: &mut ViewContext) { + self.channel_store.update(cx, |channel_store, cx| { + channel_store + .set_channel_visibility( + self.channel_id, + match selection { + Selection::Unselected => ChannelVisibility::Members, + Selection::Selected => ChannelVisibility::Public, + Selection::Indeterminate => return, + }, + cx, + ) + .detach_and_log_err(cx) }); } @@ -160,49 +149,79 @@ impl Render for ChannelModal { let Some(channel) = channel_store.channel_for_id(self.channel_id) else { return div(); }; + let channel_name = channel.name.clone(); + let channel_id = channel.id; + let visibility = channel.visibility; let mode = self.picker.read(cx).delegate.mode; v_stack() - .bg(cx.theme().colors().elevated_surface_background) + .key_context("ChannelModal") + .on_action(cx.listener(Self::toggle_mode)) + .on_action(cx.listener(Self::dismiss)) + .elevation_3(cx) .w(rems(34.)) - .child(Label::new(channel.name.clone())) - .child( - div() - .w_full() - .flex_row() - .child(Checkbox::new( - "is-public", - if channel.visibility == ChannelVisibility::Public { - ui::Selection::Selected - } else { - ui::Selection::Unselected - }, - )) - .child(Label::new("Public")), - ) .child( - div() - .w_full() - .flex_row() + v_stack() + .px_2() + .py_1() + .rounded_t(px(8.)) + .bg(cx.theme().colors().element_background) + .child(IconElement::new(Icon::Hash).size(IconSize::Medium)) + .child(Label::new(channel_name)) .child( - Button::new("manage-members", "Manage Members") - .selected(mode == Mode::ManageMembers) - .on_click(cx.listener(|this, _, cx| { - this.picker.update(cx, |picker, _| { - picker.delegate.mode = Mode::ManageMembers - }); - cx.notify(); - })), + h_stack() + .w_full() + .justify_between() + .child( + h_stack() + .gap_2() + .child( + Checkbox::new( + "is-public", + if visibility == ChannelVisibility::Public { + ui::Selection::Selected + } else { + ui::Selection::Unselected + }, + ) + .on_click(cx.listener(Self::set_channel_visiblity)), + ) + .child(Label::new("Public")), + ) + .children(if visibility == ChannelVisibility::Public { + Some(Button::new("copy-link", "Copy Link").on_click(cx.listener( + move |this, _, cx| { + if let Some(channel) = + this.channel_store.read(cx).channel_for_id(channel_id) + { + let item = ClipboardItem::new(channel.link()); + cx.write_to_clipboard(item); + } + }, + ))) + } else { + None + }), ) .child( - Button::new("invite-members", "Invite Members") - .selected(mode == Mode::InviteMembers) - .on_click(cx.listener(|this, _, cx| { - this.picker.update(cx, |picker, _| { - picker.delegate.mode = Mode::InviteMembers - }); - cx.notify(); - })), + div() + .w_full() + .flex() + .flex_row() + .child( + Button::new("manage-members", "Manage Members") + .selected(mode == Mode::ManageMembers) + .on_click(cx.listener(|this, _, cx| { + this.set_mode(Mode::ManageMembers, cx); + })), + ) + .child( + Button::new("invite-members", "Invite Members") + .selected(mode == Mode::InviteMembers) + .on_click(cx.listener(|this, _, cx| { + this.set_mode(Mode::InviteMembers, cx); + })), + ), ), ) .child(self.picker.clone()) @@ -226,11 +245,11 @@ pub struct ChannelModalDelegate { mode: Mode, match_candidates: Vec, members: Vec, - // context_menu: ViewHandle, + context_menu: Option<(View, Subscription)>, } impl PickerDelegate for ChannelModalDelegate { - type ListItem = Div; + type ListItem = ListItem; fn placeholder_text(&self) -> Arc { "Search collaborator by username...".into() @@ -310,11 +329,11 @@ impl PickerDelegate for ChannelModalDelegate { if let Some((selected_user, role)) = self.user_at_index(self.selected_index) { match self.mode { Mode::ManageMembers => { - self.show_context_menu(role.unwrap_or(ChannelRole::Member), cx) + self.show_context_menu(selected_user, role.unwrap_or(ChannelRole::Member), cx) } Mode::InviteMembers => match self.member_status(selected_user.id, cx) { Some(proto::channel_member::Kind::Invitee) => { - self.remove_selected_member(cx); + self.remove_member(selected_user.id, cx); } Some(proto::channel_member::Kind::AncestorMember) | None => { self.invite_member(selected_user, cx) @@ -326,11 +345,13 @@ impl PickerDelegate for ChannelModalDelegate { } fn dismissed(&mut self, cx: &mut ViewContext>) { - self.channel_modal - .update(cx, |_, cx| { - cx.emit(DismissEvent); - }) - .ok(); + if self.context_menu.is_none() { + self.channel_modal + .update(cx, |_, cx| { + cx.emit(DismissEvent); + }) + .ok(); + } } fn render_match( @@ -339,129 +360,54 @@ impl PickerDelegate for ChannelModalDelegate { selected: bool, cx: &mut ViewContext>, ) -> Option { - None - // let full_theme = &theme::current(cx); - // let theme = &full_theme.collab_panel.channel_modal; - // let tabbed_modal = &full_theme.collab_panel.tabbed_modal; - // let (user, role) = self.user_at_index(ix).unwrap(); - // let request_status = self.member_status(user.id, cx); - - // let style = tabbed_modal - // .picker - // .item - // .in_state(selected) - // .style_for(mouse_state); - - // let in_manage = matches!(self.mode, Mode::ManageMembers); - - // let mut result = Flex::row() - // .with_children(user.avatar.clone().map(|avatar| { - // Image::from_data(avatar) - // .with_style(theme.contact_avatar) - // .aligned() - // .left() - // })) - // .with_child( - // Label::new(user.github_login.clone(), style.label.clone()) - // .contained() - // .with_style(theme.contact_username) - // .aligned() - // .left(), - // ) - // .with_children({ - // (in_manage && request_status == Some(proto::channel_member::Kind::Invitee)).then( - // || { - // Label::new("Invited", theme.member_tag.text.clone()) - // .contained() - // .with_style(theme.member_tag.container) - // .aligned() - // .left() - // }, - // ) - // }) - // .with_children(if in_manage && role == Some(ChannelRole::Admin) { - // Some( - // Label::new("Admin", theme.member_tag.text.clone()) - // .contained() - // .with_style(theme.member_tag.container) - // .aligned() - // .left(), - // ) - // } else if in_manage && role == Some(ChannelRole::Guest) { - // Some( - // Label::new("Guest", theme.member_tag.text.clone()) - // .contained() - // .with_style(theme.member_tag.container) - // .aligned() - // .left(), - // ) - // } else { - // None - // }) - // .with_children({ - // let svg = match self.mode { - // Mode::ManageMembers => Some( - // Svg::new("icons/ellipsis.svg") - // .with_color(theme.member_icon.color) - // .constrained() - // .with_width(theme.member_icon.icon_width) - // .aligned() - // .constrained() - // .with_width(theme.member_icon.button_width) - // .with_height(theme.member_icon.button_width) - // .contained() - // .with_style(theme.member_icon.container), - // ), - // Mode::InviteMembers => match request_status { - // Some(proto::channel_member::Kind::Member) => Some( - // Svg::new("icons/check.svg") - // .with_color(theme.member_icon.color) - // .constrained() - // .with_width(theme.member_icon.icon_width) - // .aligned() - // .constrained() - // .with_width(theme.member_icon.button_width) - // .with_height(theme.member_icon.button_width) - // .contained() - // .with_style(theme.member_icon.container), - // ), - // Some(proto::channel_member::Kind::Invitee) => Some( - // Svg::new("icons/check.svg") - // .with_color(theme.invitee_icon.color) - // .constrained() - // .with_width(theme.invitee_icon.icon_width) - // .aligned() - // .constrained() - // .with_width(theme.invitee_icon.button_width) - // .with_height(theme.invitee_icon.button_width) - // .contained() - // .with_style(theme.invitee_icon.container), - // ), - // Some(proto::channel_member::Kind::AncestorMember) | None => None, - // }, - // }; - - // svg.map(|svg| svg.aligned().flex_float().into_any()) - // }) - // .contained() - // .with_style(style.container) - // .constrained() - // .with_height(tabbed_modal.row_height) - // .into_any(); - - // if selected { - // result = Stack::new() - // .with_child(result) - // .with_child( - // ChildView::new(&self.context_menu, cx) - // .aligned() - // .top() - // .right(), - // ) - // .into_any(); - // } - - // result + let (user, role) = self.user_at_index(ix)?; + let request_status = self.member_status(user.id, cx); + + Some( + ListItem::new(ix) + .inset(true) + .selected(selected) + .start_slot(Avatar::new(user.avatar_uri.clone())) + .child(Label::new(user.github_login.clone())) + .end_slot(h_stack().gap_2().map(|slot| { + match self.mode { + Mode::ManageMembers => slot + .children( + if request_status == Some(proto::channel_member::Kind::Invitee) { + Some(Label::new("Invited")) + } else { + None + }, + ) + .children(match role { + Some(ChannelRole::Admin) => Some(Label::new("Admin")), + Some(ChannelRole::Guest) => Some(Label::new("Guest")), + _ => None, + }) + .child(IconButton::new("ellipsis", Icon::Ellipsis)) + .children( + if let (Some((menu, _)), true) = (&self.context_menu, selected) { + Some( + overlay() + .anchor(gpui::AnchorCorner::TopLeft) + .child(menu.clone()), + ) + } else { + None + }, + ), + Mode::InviteMembers => match request_status { + Some(proto::channel_member::Kind::Invitee) => { + slot.children(Some(Label::new("Invited"))) + } + Some(proto::channel_member::Kind::Member) => { + slot.children(Some(Label::new("Member"))) + } + _ => slot, + }, + } + })), + ) } } @@ -495,21 +441,20 @@ impl ChannelModalDelegate { } } - fn toggle_selected_member_admin(&mut self, cx: &mut ViewContext>) -> Option<()> { - let (user, role) = self.user_at_index(self.selected_index)?; - let new_role = if role == Some(ChannelRole::Admin) { - ChannelRole::Member - } else { - ChannelRole::Admin - }; + fn set_user_role( + &mut self, + user_id: UserId, + new_role: ChannelRole, + cx: &mut ViewContext>, + ) -> Option<()> { let update = self.channel_store.update(cx, |store, cx| { - store.set_member_role(self.channel_id, user.id, new_role, cx) + store.set_member_role(self.channel_id, user_id, new_role, cx) }); cx.spawn(|picker, mut cx| async move { update.await?; picker.update(&mut cx, |picker, cx| { let this = &mut picker.delegate; - if let Some(member) = this.members.iter_mut().find(|m| m.user.id == user.id) { + if let Some(member) = this.members.iter_mut().find(|m| m.user.id == user_id) { member.role = new_role; } cx.focus_self(); @@ -520,9 +465,7 @@ impl ChannelModalDelegate { Some(()) } - fn remove_selected_member(&mut self, cx: &mut ViewContext>) -> Option<()> { - let (user, _) = self.user_at_index(self.selected_index)?; - let user_id = user.id; + fn remove_member(&mut self, user_id: UserId, cx: &mut ViewContext>) -> Option<()> { let update = self.channel_store.update(cx, |store, cx| { store.remove_member(self.channel_id, user_id, cx) }); @@ -546,7 +489,7 @@ impl ChannelModalDelegate { .selected_index .min(this.matching_member_indices.len().saturating_sub(1)); - cx.focus_self(); + picker.focus(cx); cx.notify(); }) }) @@ -579,24 +522,55 @@ impl ChannelModalDelegate { .detach_and_log_err(cx); } - fn show_context_menu(&mut self, role: ChannelRole, cx: &mut ViewContext>) { - // self.context_menu.update(cx, |context_menu, cx| { - // context_menu.show( - // Default::default(), - // AnchorCorner::TopRight, - // vec![ - // ContextMenuItem::action("Remove", RemoveMember), - // ContextMenuItem::action( - // if role == ChannelRole::Admin { - // "Make non-admin" - // } else { - // "Make admin" - // }, - // ToggleMemberAdmin, - // ), - // ], - // cx, - // ) - // }) + fn show_context_menu( + &mut self, + user: Arc, + role: ChannelRole, + cx: &mut ViewContext>, + ) { + let user_id = user.id; + let picker = cx.view().clone(); + let context_menu = ContextMenu::build(cx, |mut menu, _cx| { + menu = menu.entry("Remove Member", { + let picker = picker.clone(); + move |cx| { + picker.update(cx, |picker, cx| { + picker.delegate.remove_member(user_id, cx); + }) + } + }); + + let picker = picker.clone(); + match role { + ChannelRole::Admin => { + menu = menu.entry("Revoke Admin", move |cx| { + picker.update(cx, |picker, cx| { + picker + .delegate + .set_user_role(user_id, ChannelRole::Member, cx); + }) + }); + } + ChannelRole::Member => { + menu = menu.entry("Make Admin", move |cx| { + picker.update(cx, |picker, cx| { + picker + .delegate + .set_user_role(user_id, ChannelRole::Admin, cx); + }) + }); + } + _ => {} + }; + + menu + }); + cx.focus_view(&context_menu); + let subscription = cx.subscribe(&context_menu, |picker, _, _: &DismissEvent, cx| { + picker.delegate.context_menu = None; + picker.focus(cx); + cx.notify(); + }); + self.context_menu = Some((context_menu, subscription)); } } diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 71799a6e00d5975cf12085131547a0f7c5af7cb3..f7ebddd0fea2b725e45d798b1a75e1d76ed3b5f7 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -2662,13 +2662,6 @@ impl<'a, V: 'static> ViewContext<'a, V> { self.defer(|view, cx| view.focus_handle(cx).focus(cx)) } - pub fn dismiss_self(&mut self) - where - V: ManagedView, - { - self.defer(|_, cx| cx.emit(DismissEvent)) - } - pub fn listener( &self, f: impl Fn(&mut V, &E, &mut ViewContext) + 'static, diff --git a/crates/picker2/src/picker2.rs b/crates/picker2/src/picker2.rs index 70180112f96bbc795d18db19869365dc227f5844..8a75996f482c2c692adf95eed1015ef783d8ee1f 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -239,7 +239,7 @@ impl Render for Picker { ); div() - .key_context("picker") + .key_context("Picker") .size_full() .when_some(self.width, |el, width| { el.w(width) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 250272b19882f031ab7af438bf3cfea7906bcec8..8fce15d1c69d0fcf97f8ac1757874be4884950b6 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -72,11 +72,11 @@ impl ContextMenu { pub fn entry( mut self, label: impl Into, - on_click: impl Fn(&mut WindowContext) + 'static, + handler: impl Fn(&mut WindowContext) + 'static, ) -> Self { self.items.push(ContextMenuItem::Entry { label: label.into(), - handler: Rc::new(on_click), + handler: Rc::new(handler), icon: None, action: None, }); @@ -114,6 +114,7 @@ impl ContextMenu { pub fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext) { cx.emit(DismissEvent); + cx.emit(DismissEvent); } fn select_first(&mut self, _: &SelectFirst, cx: &mut ViewContext) { diff --git a/crates/ui2/src/components/icon.rs b/crates/ui2/src/components/icon.rs index ca50cae7f8936e50dbc66be2def222589a571207..a168f97a50f047fbf8d338a779c46f6cfef57639 100644 --- a/crates/ui2/src/components/icon.rs +++ b/crates/ui2/src/components/icon.rs @@ -51,6 +51,7 @@ pub enum Icon { CopilotDisabled, Dash, Disconnected, + Ellipsis, Envelope, ExternalLink, ExclamationTriangle, @@ -133,6 +134,7 @@ impl Icon { Icon::CopilotDisabled => "icons/copilot_disabled.svg", Icon::Dash => "icons/dash.svg", Icon::Disconnected => "icons/disconnected.svg", + Icon::Ellipsis => "icons/ellipsis.svg", Icon::Envelope => "icons/feedback.svg", Icon::ExclamationTriangle => "icons/warning.svg", Icon::ExternalLink => "icons/external_link.svg", From a9b1273e2bd9d446bd11b7f35b2792f4ef6b0d53 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 Dec 2023 12:06:47 -0800 Subject: [PATCH 4/4] Clean up commented code Co-authored-by: Nathan --- crates/collab_ui2/src/collab_panel.rs | 316 +++----------------------- 1 file changed, 34 insertions(+), 282 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index 3df8f06d3b328f287086eef1e048274a8008ca71..b7dd24b9ab5fc0b4eea338316fac95060c468d47 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -1,128 +1,45 @@ mod channel_modal; mod contact_finder; -// use crate::{ -// channel_view::{self, ChannelView}, -// chat_panel::ChatPanel, -// face_pile::FacePile, -// panel_settings, CollaborationPanelSettings, -// }; -// use anyhow::Result; -// use call::ActiveCall; -// use channel::{Channel, ChannelEvent, ChannelId, ChannelStore}; -// use channel_modal::ChannelModal; -// use client::{ -// proto::{self, PeerId}, -// Client, Contact, User, UserStore, -// }; +use self::channel_modal::ChannelModal; +use crate::{ + channel_view::ChannelView, chat_panel::ChatPanel, face_pile::FacePile, + CollaborationPanelSettings, +}; +use call::ActiveCall; +use channel::{Channel, ChannelEvent, ChannelId, ChannelStore}; +use client::{Client, Contact, User, UserStore}; use contact_finder::ContactFinder; +use db::kvp::KEY_VALUE_STORE; +use editor::Editor; +use feature_flags::{ChannelsAlpha, FeatureFlagAppExt, FeatureFlagViewExt}; +use fuzzy::{match_strings, StringMatchCandidate}; +use gpui::{ + actions, canvas, div, fill, list, overlay, point, prelude::*, px, serde_json, AnyElement, + AppContext, AsyncWindowContext, Bounds, ClipboardItem, DismissEvent, Div, EventEmitter, + FocusHandle, Focusable, FocusableView, InteractiveElement, IntoElement, ListOffset, ListState, + Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, + SharedString, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, +}; use menu::{Cancel, Confirm, SelectNext, SelectPrev}; +use project::{Fs, Project}; use rpc::proto::{self, PeerId}; +use serde_derive::{Deserialize, Serialize}; +use settings::{Settings, SettingsStore}; use smallvec::SmallVec; +use std::{mem, sync::Arc}; use theme::{ActiveTheme, ThemeSettings}; -// use context_menu::{ContextMenu, ContextMenuItem}; -// use db::kvp::KEY_VALUE_STORE; -// use drag_and_drop::{DragAndDrop, Draggable}; -// use editor::{Cancel, Editor}; -// use feature_flags::{ChannelsAlpha, FeatureFlagAppExt, FeatureFlagViewExt}; -// use futures::StreamExt; -// use fuzzy::{match_strings, StringMatchCandidate}; -// use gpui::{ -// actions, -// elements::{ -// Canvas, ChildView, Component, ContainerStyle, Empty, Flex, Image, Label, List, ListOffset, -// ListState, 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, ClipboardItem, Element, Entity, FontCache, -// ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, -// }; -// use menu::{Confirm, SelectNext, SelectPrev}; -// use project::{Fs, Project}; -// use serde_derive::{Deserialize, Serialize}; -// use settings::SettingsStore; -// use std::{borrow::Cow, hash::Hash, mem, sync::Arc}; -// use theme::{components::ComponentExt, IconButton, Interactive}; -// use util::{maybe, ResultExt, TryFutureExt}; -// use workspace::{ -// dock::{DockPosition, Panel}, -// item::ItemHandle, -// FollowNextCollaborator, Workspace, -// }; - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct ToggleCollapse { -// location: ChannelId, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct NewChannel { -// location: ChannelId, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct RenameChannel { -// channel_id: ChannelId, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct ToggleSelectedIx { -// ix: usize, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct RemoveChannel { -// channel_id: ChannelId, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct InviteMembers { -// channel_id: ChannelId, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct ManageMembers { -// channel_id: ChannelId, -// } - -#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] -pub struct OpenChannelNotes { - pub channel_id: ChannelId, -} - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// pub struct JoinChannelCall { -// pub channel_id: u64, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// pub struct JoinChannelChat { -// pub channel_id: u64, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// pub struct CopyChannelLink { -// pub channel_id: u64, -// } - -// #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct StartMoveChannelFor { -// channel_id: ChannelId, -// } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -// struct MoveChannel { -// to: ChannelId, -// } - -impl_actions!(collab_panel, [OpenChannelNotes]); +use ui::prelude::*; +use ui::{ + h_stack, v_stack, Avatar, Button, Color, ContextMenu, Icon, IconButton, IconElement, IconSize, + Label, ListHeader, ListItem, Tooltip, +}; +use util::{maybe, ResultExt, TryFutureExt}; +use workspace::{ + dock::{DockPosition, Panel, PanelEvent}, + notifications::NotifyResultExt, + Workspace, +}; actions!( collab_panel, @@ -138,25 +55,6 @@ actions!( ] ); -// impl_actions!( -// collab_panel, -// [ -// RemoveChannel, -// NewChannel, -// InviteMembers, -// ManageMembers, -// RenameChannel, -// ToggleCollapse, -// OpenChannelNotes, -// JoinChannelCall, -// JoinChannelChat, -// CopyChannelLink, -// StartMoveChannelFor, -// MoveChannel, -// ToggleSelectedIx -// ] -// ); - #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct ChannelMoveClipboard { channel_id: ChannelId, @@ -164,44 +62,6 @@ struct ChannelMoveClipboard { const COLLABORATION_PANEL_KEY: &'static str = "CollaborationPanel"; -use std::{mem, sync::Arc}; - -use call::ActiveCall; -use channel::{Channel, ChannelEvent, ChannelId, ChannelStore}; -use client::{Client, Contact, User, UserStore}; -use db::kvp::KEY_VALUE_STORE; -use editor::Editor; -use feature_flags::{ChannelsAlpha, FeatureFlagAppExt, FeatureFlagViewExt}; -use fuzzy::{match_strings, StringMatchCandidate}; -use gpui::{ - actions, canvas, div, fill, impl_actions, list, overlay, point, prelude::*, px, serde_json, - AnyElement, AppContext, AsyncWindowContext, Bounds, ClipboardItem, DismissEvent, Div, - EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement, IntoElement, - ListOffset, ListState, Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, - Render, RenderOnce, SharedString, Styled, Subscription, Task, View, ViewContext, VisualContext, - WeakView, -}; -use project::{Fs, Project}; -use serde_derive::{Deserialize, Serialize}; -use settings::{Settings, SettingsStore}; -use ui::prelude::*; -use ui::{ - h_stack, v_stack, Avatar, Button, Color, ContextMenu, Icon, IconButton, IconElement, IconSize, - Label, ListHeader, ListItem, Tooltip, -}; -use util::{maybe, ResultExt, TryFutureExt}; -use workspace::{ - dock::{DockPosition, Panel, PanelEvent}, - notifications::NotifyResultExt, - Workspace, -}; - -use crate::channel_view::ChannelView; -use crate::chat_panel::ChatPanel; -use crate::{face_pile::FacePile, CollaborationPanelSettings}; - -use self::channel_modal::ChannelModal; - pub fn init(cx: &mut AppContext) { cx.observe_new_views(|workspace: &mut Workspace, _| { workspace.register_action(|workspace, _: &ToggleFocus, cx| { @@ -209,69 +69,6 @@ pub fn init(cx: &mut AppContext) { }); }) .detach(); - // contact_finder::init(cx); - // channel_modal::init(cx); - // channel_view::init(cx); - - // cx.add_action(CollabPanel::cancel); - // cx.add_action(CollabPanel::select_next); - // cx.add_action(CollabPanel::select_prev); - // cx.add_action(CollabPanel::confirm); - // cx.add_action(CollabPanel::insert_space); - // cx.add_action(CollabPanel::remove); - // cx.add_action(CollabPanel::remove_selected_channel); - // cx.add_action(CollabPanel::show_inline_context_menu); - // cx.add_action(CollabPanel::new_subchannel); - // cx.add_action(CollabPanel::invite_members); - // cx.add_action(CollabPanel::manage_members); - // cx.add_action(CollabPanel::rename_selected_channel); - // cx.add_action(CollabPanel::rename_channel); - // cx.add_action(CollabPanel::toggle_channel_collapsed_action); - // cx.add_action(CollabPanel::collapse_selected_channel); - // cx.add_action(CollabPanel::expand_selected_channel); - // cx.add_action(CollabPanel::open_channel_notes); - // cx.add_action(CollabPanel::join_channel_chat); - // cx.add_action(CollabPanel::copy_channel_link); - - // cx.add_action( - // |panel: &mut CollabPanel, action: &ToggleSelectedIx, cx: &mut ViewContext| { - // if panel.selection.take() != Some(action.ix) { - // panel.selection = Some(action.ix) - // } - - // cx.notify(); - // }, - // ); - - // cx.add_action( - // |panel: &mut CollabPanel, _: &MoveSelected, cx: &mut ViewContext| { - // let Some(clipboard) = panel.channel_clipboard.take() else { - // return; - // }; - // let Some(selected_channel) = panel.selected_channel() else { - // return; - // }; - - // panel - // .channel_store - // .update(cx, |channel_store, cx| { - // channel_store.move_channel(clipboard.channel_id, Some(selected_channel.id), cx) - // }) - // .detach_and_log_err(cx) - // }, - // ); - - // cx.add_action( - // |panel: &mut CollabPanel, action: &MoveChannel, cx: &mut ViewContext| { - // if let Some(clipboard) = panel.channel_clipboard.take() { - // panel.channel_store.update(cx, |channel_store, cx| { - // channel_store - // .move_channel(clipboard.channel_id, Some(action.to), cx) - // .detach_and_log_err(cx) - // }) - // } - // }, - // ); } #[derive(Debug)] @@ -317,7 +114,6 @@ pub struct CollabPanel { collapsed_sections: Vec
, collapsed_channels: Vec, workspace: WeakView, - // context_menu_on_selected: bool, } #[derive(Serialize, Deserialize)] @@ -326,13 +122,6 @@ struct SerializedCollabPanel { collapsed_channels: Option>, } -// #[derive(Debug)] -// pub enum Event { -// DockPositionChanged, -// Focus, -// Dismissed, -// } - #[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)] enum Section { ActiveCall, @@ -1131,40 +920,6 @@ impl CollabPanel { } } - // fn render_contact_placeholder( - // &self, - // theme: &theme::CollabPanel, - // is_selected: bool, - // cx: &mut ViewContext, - // ) -> AnyElement { - // enum AddContacts {} - // MouseEventHandler::new::(0, cx, |state, _| { - // let style = theme.list_empty_state.style_for(is_selected, state); - // Flex::row() - // .with_child( - // Svg::new("icons/plus.svg") - // .with_color(theme.list_empty_icon.color) - // .constrained() - // .with_width(theme.list_empty_icon.width) - // .aligned() - // .left(), - // ) - // .with_child( - // Label::new("Add a contact", style.text.clone()) - // .contained() - // .with_style(theme.list_empty_label_container), - // ) - // .align_children_center() - // .contained() - // .with_style(style.container) - // .into_any() - // }) - // .on_click(MouseButton::Left, |_, this, cx| { - // this.toggle_contact_finder(cx); - // }) - // .into_any() - // } - fn render_channel_notes( &self, channel_id: ChannelId, @@ -1752,9 +1507,6 @@ impl CollabPanel { } } - // // Should move to the filter editor if clicking on it - // // Should move selection to the channel editor if activating it - fn remove_contact(&mut self, user_id: u64, github_login: &str, cx: &mut ViewContext) { let user_store = self.user_store.clone(); let prompt_message = format!(