From 08de0d88b1ea63b47d337e45608ad3c2afccc51e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 26 Jan 2024 10:07:51 -0700 Subject: [PATCH] Update channel moving to match --- crates/collab/src/db/queries/channels.rs | 6 +-- crates/collab_ui/src/collab_panel.rs | 53 ++++++++++++++++------- crates/gpui/src/elements/div.rs | 27 +++++++++--- crates/project_panel/src/project_panel.rs | 2 +- crates/rpc/proto/zed.proto | 2 + crates/workspace/src/pane.rs | 12 +++-- 6 files changed, 72 insertions(+), 30 deletions(-) diff --git a/crates/collab/src/db/queries/channels.rs b/crates/collab/src/db/queries/channels.rs index 7276d6cc17..b7785b0f7f 100644 --- a/crates/collab/src/db/queries/channels.rs +++ b/crates/collab/src/db/queries/channels.rs @@ -995,20 +995,20 @@ impl Database { let new_parent = self.get_channel_internal(new_parent_id, &*tx).await?; if new_parent.root_id() != channel.root_id() { - Err(anyhow!("cannot move a channel into a different root"))?; + Err(anyhow!(ErrorCode::WrongMoveTarget))?; } if new_parent .ancestors_including_self() .any(|id| id == channel.id) { - Err(anyhow!("cannot move a channel into one of its descendants"))?; + Err(anyhow!(ErrorCode::CircularNesting))?; } if channel.visibility == ChannelVisibility::Public && new_parent.visibility != ChannelVisibility::Public { - Err(anyhow!("public channels must descend from public channels"))?; + Err(anyhow!(ErrorCode::BadPublicNesting))?; } let root_id = channel.root_id(); diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index e82ab60bc9..8a552224ca 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -1585,14 +1585,27 @@ impl CollabPanel { cx: &mut ViewContext, ) { if let Some(clipboard) = self.channel_clipboard.take() { - self.channel_store - .update(cx, |channel_store, cx| { - channel_store.move_channel(clipboard.channel_id, to_channel_id, cx) - }) - .detach_and_prompt_err("Failed to move channel", cx, |_, _| None) + self.move_channel(clipboard.channel_id, to_channel_id, cx) } } + fn move_channel(&self, channel_id: ChannelId, to: ChannelId, cx: &mut ViewContext) { + self.channel_store + .update(cx, |channel_store, cx| { + channel_store.move_channel(channel_id, to, cx) + }) + .detach_and_prompt_err("Failed to move channel", cx, |e, _| match e.error_code() { + ErrorCode::BadPublicNesting => { + Some("Public channels must have public parents".into()) + } + ErrorCode::CircularNesting => Some("You cannot move a channel into itself".into()), + ErrorCode::WrongMoveTarget => { + Some("You cannot move a channel into a different root channel".into()) + } + _ => None, + }) + } + fn open_channel_notes(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { if let Some(workspace) = self.workspace.upgrade() { ChannelView::open(channel_id, workspace, cx).detach(); @@ -2285,6 +2298,7 @@ impl CollabPanel { }; let width = self.width.unwrap_or(px(240.)); + let root_id = channel.root_id(); div() .h_6() @@ -2292,19 +2306,28 @@ impl CollabPanel { .group("") .flex() .w_full() - .on_drag(channel.clone(), move |channel, cx| { - cx.new_view(|_| DraggedChannelView { - channel: channel.clone(), - width, + .when(!channel.is_root_channel(), |el| { + el.on_drag(channel.clone(), move |channel, cx| { + cx.new_view(|_| DraggedChannelView { + channel: channel.clone(), + width, + }) }) }) - .drag_over::(|style| style.bg(cx.theme().colors().ghost_element_hover)) + .drag_over::({ + move |style, dragged_channel: &Channel, cx| { + if dragged_channel.root_id() == root_id { + style.bg(cx.theme().colors().ghost_element_hover) + } else { + style + } + } + }) .on_drop(cx.listener(move |this, dragged_channel: &Channel, cx| { - this.channel_store - .update(cx, |channel_store, cx| { - channel_store.move_channel(dragged_channel.id, channel_id, cx) - }) - .detach_and_prompt_err("Failed to move channel", cx, |_, _| None) + if dragged_channel.root_id() != root_id { + return; + } + this.move_channel(dragged_channel.id, channel_id, cx); })) .child( ListItem::new(channel_id as usize) diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index a0bbf6fc79..6d529213f0 100644 --- a/crates/gpui/src/elements/div.rs +++ b/crates/gpui/src/elements/div.rs @@ -782,10 +782,20 @@ pub trait InteractiveElement: Sized { } /// Apply the given style when the given data type is dragged over this element - fn drag_over(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self { - self.interactivity() - .drag_over_styles - .push((TypeId::of::(), f(StyleRefinement::default()))); + fn drag_over( + mut self, + f: impl 'static + Fn(StyleRefinement, &S, &WindowContext) -> StyleRefinement, + ) -> Self { + self.interactivity().drag_over_styles.push(( + TypeId::of::(), + Box::new(move |currently_dragged: &dyn Any, cx| { + f( + StyleRefinement::default(), + currently_dragged.downcast_ref::().unwrap(), + cx, + ) + }), + )); self } @@ -1174,7 +1184,10 @@ pub struct Interactivity { pub(crate) group_hover_style: Option, pub(crate) active_style: Option>, pub(crate) group_active_style: Option, - pub(crate) drag_over_styles: Vec<(TypeId, StyleRefinement)>, + pub(crate) drag_over_styles: Vec<( + TypeId, + Box StyleRefinement>, + )>, pub(crate) group_drag_over_styles: Vec<(TypeId, GroupStyle)>, pub(crate) mouse_down_listeners: Vec, pub(crate) mouse_up_listeners: Vec, @@ -1980,7 +1993,7 @@ impl Interactivity { } } - for (state_type, drag_over_style) in &self.drag_over_styles { + for (state_type, build_drag_over_style) in &self.drag_over_styles { if *state_type == drag.value.as_ref().type_id() && bounds .intersect(&cx.content_mask().bounds) @@ -1990,7 +2003,7 @@ impl Interactivity { cx.stacking_order(), ) { - style.refine(drag_over_style); + style.refine(&build_drag_over_style(drag.value.as_ref(), cx)); } } } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index b20866fc65..f261089be0 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1368,7 +1368,7 @@ impl ProjectPanel { entry_id: *entry_id, }) }) - .drag_over::(|style| { + .drag_over::(|style, _, cx| { style.bg(cx.theme().colors().drop_target_background) }) .on_drop(cx.listener(move |this, dragged_id: &ProjectEntryId, cx| { diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index a6a34a9e5e..18f9b1f1e8 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -214,6 +214,8 @@ enum ErrorCode { NeedsCla = 7; NotARootChannel = 8; BadPublicNesting = 9; + CircularNesting = 10; + WrongMoveTarget = 11; } message Test { diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 2336230c86..55ae875fef 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1334,8 +1334,12 @@ impl Pane { }, |tab, cx| cx.new_view(|_| tab.clone()), ) - .drag_over::(|tab| tab.bg(cx.theme().colors().drop_target_background)) - .drag_over::(|tab| tab.bg(cx.theme().colors().drop_target_background)) + .drag_over::(|tab, _, cx| { + tab.bg(cx.theme().colors().drop_target_background) + }) + .drag_over::(|tab, _, cx| { + tab.bg(cx.theme().colors().drop_target_background) + }) .when_some(self.can_drop_predicate.clone(), |this, p| { this.can_drop(move |a, cx| p(a, cx)) }) @@ -1505,10 +1509,10 @@ impl Pane { .child("") .h_full() .flex_grow() - .drag_over::(|bar| { + .drag_over::(|bar, _, cx| { bar.bg(cx.theme().colors().drop_target_background) }) - .drag_over::(|bar| { + .drag_over::(|bar, _, cx| { bar.bg(cx.theme().colors().drop_target_background) }) .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {