diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 11cc50a03e..f4d36ee95b 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -13,6 +13,7 @@ "cmd-up": "menu::SelectFirst", "cmd-down": "menu::SelectLast", "enter": "menu::Confirm", + "ctrl-enter": "menu::ShowContextMenu", "cmd-enter": "menu::SecondaryConfirm", "escape": "menu::Cancel", "ctrl-c": "menu::Cancel", @@ -550,6 +551,13 @@ "alt-shift-f": "project_panel::NewSearchInDirectory" } }, + { + "context": "CollabPanel", + "bindings": { + "ctrl-backspace": "collab_panel::Remove", + "space": "menu::Confirm" + } + }, { "context": "ChannelModal", "bindings": { diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 2b39678f5e..85e0d80cce 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -15,7 +15,7 @@ use gpui::{ actions, elements::{ Canvas, ChildView, Empty, Flex, Image, Label, List, ListOffset, ListState, - MouseEventHandler, Orientation, Padding, ParentElement, Stack, Svg, + MouseEventHandler, Orientation, OverlayPositionMode, Padding, ParentElement, Stack, Svg, }, geometry::{ rect::RectF, @@ -64,7 +64,7 @@ struct ManageMembers { channel_id: u64, } -actions!(collab_panel, [ToggleFocus]); +actions!(collab_panel, [ToggleFocus, Remove, Secondary]); impl_actions!( collab_panel, @@ -82,7 +82,9 @@ pub fn init(_client: Arc, cx: &mut AppContext) { cx.add_action(CollabPanel::select_next); cx.add_action(CollabPanel::select_prev); cx.add_action(CollabPanel::confirm); - cx.add_action(CollabPanel::remove_channel); + cx.add_action(CollabPanel::remove); + cx.add_action(CollabPanel::remove_channel_action); + 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); @@ -113,6 +115,7 @@ pub struct CollabPanel { subscriptions: Vec, collapsed_sections: Vec
, workspace: WeakViewHandle, + context_menu_on_selected: bool, } #[derive(Serialize, Deserialize)] @@ -274,7 +277,26 @@ impl CollabPanel { ) } ListEntry::Channel(channel) => { - this.render_channel(&*channel, &theme.collab_panel, is_selected, cx) + let channel_row = this.render_channel( + &*channel, + &theme.collab_panel, + is_selected, + cx, + ); + + if is_selected && this.context_menu_on_selected { + Stack::new() + .with_child(channel_row) + .with_child( + ChildView::new(&this.context_menu, cx) + .aligned() + .bottom() + .right(), + ) + .into_any() + } else { + return channel_row; + } } ListEntry::ChannelInvite(channel) => Self::render_channel_invite( channel.clone(), @@ -332,6 +354,7 @@ impl CollabPanel { collapsed_sections: Vec::default(), workspace: workspace.weak_handle(), client: workspace.app_state().client.clone(), + context_menu_on_selected: true, list_state, }; @@ -1321,6 +1344,7 @@ impl CollabPanel { cx: &mut ViewContext, ) -> AnyElement { let channel_id = channel.id; + MouseEventHandler::::new(channel.id as usize, cx, |state, cx| { Flex::row() .with_child( @@ -1367,7 +1391,7 @@ impl CollabPanel { this.join_channel(channel_id, cx); }) .on_click(MouseButton::Right, move |e, this, cx| { - this.deploy_channel_context_menu(e.position, channel_id, cx); + this.deploy_channel_context_menu(Some(e.position), channel_id, cx); }) .into_any() } @@ -1573,15 +1597,27 @@ impl CollabPanel { fn deploy_channel_context_menu( &mut self, - position: Vector2F, + position: Option, channel_id: u64, cx: &mut ViewContext, ) { if self.channel_store.read(cx).is_user_admin(channel_id) { + self.context_menu_on_selected = position.is_none(); + self.context_menu.update(cx, |context_menu, cx| { + context_menu.set_position_mode(if self.context_menu_on_selected { + OverlayPositionMode::Local + } else { + OverlayPositionMode::Window + }); + context_menu.show( - position, - gpui::elements::AnchorCorner::BottomLeft, + position.unwrap_or_default(), + if self.context_menu_on_selected { + gpui::elements::AnchorCorner::TopRight + } else { + gpui::elements::AnchorCorner::BottomLeft + }, vec![ ContextMenuItem::action("New Channel", NewChannel { channel_id }), ContextMenuItem::action("Remove Channel", RemoveChannel { channel_id }), @@ -1591,6 +1627,8 @@ impl CollabPanel { cx, ); }); + + cx.notify(); } } @@ -1755,6 +1793,33 @@ impl CollabPanel { self.show_channel_modal(action.channel_id, channel_modal::Mode::ManageMembers, cx); } + // TODO: Make join into a toggle + // TODO: Make enter work on channel editor + fn remove(&mut self, _: &Remove, cx: &mut ViewContext) { + if let Some(channel) = self.selected_channel() { + self.remove_channel(channel.id, cx) + } + } + + fn rename(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext) {} + + fn show_inline_context_menu(&mut self, _: &menu::ShowContextMenu, cx: &mut ViewContext) { + let Some(channel) = self.selected_channel() else { + return; + }; + + self.deploy_channel_context_menu(None, channel.id, cx); + } + + fn selected_channel(&self) -> Option<&Arc> { + self.selection + .and_then(|ix| self.entries.get(ix)) + .and_then(|entry| match entry { + ListEntry::Channel(channel) => Some(channel), + _ => None, + }) + } + fn show_channel_modal( &mut self, channel_id: ChannelId, @@ -1788,8 +1853,11 @@ impl CollabPanel { .detach(); } - fn remove_channel(&mut self, action: &RemoveChannel, cx: &mut ViewContext) { - let channel_id = action.channel_id; + fn remove_channel_action(&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) { let prompt_message = format!( @@ -1818,6 +1886,9 @@ 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!( @@ -1969,7 +2040,10 @@ impl View for CollabPanel { .with_width(self.size(cx)) .into_any(), ) - .with_child(ChildView::new(&self.context_menu, cx)) + .with_children( + (!self.context_menu_on_selected) + .then(|| ChildView::new(&self.context_menu, cx)), + ) .into_any() }) .on_click(MouseButton::Left, |_, _, cx| cx.focus_self()) diff --git a/crates/menu/src/menu.rs b/crates/menu/src/menu.rs index b0f1a9c6c8..519ad1ecd0 100644 --- a/crates/menu/src/menu.rs +++ b/crates/menu/src/menu.rs @@ -7,6 +7,7 @@ gpui::actions!( SelectPrev, SelectNext, SelectFirst, - SelectLast + SelectLast, + ShowContextMenu ] );