From 516bd13474ab2a6868191690d78940dc0a58745b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Jun 2022 17:01:48 +0200 Subject: [PATCH] Add tooltip to follow collaborators --- crates/contacts_panel/src/contacts_panel.rs | 6 +- crates/editor/src/element.rs | 2 +- crates/gpui/src/elements.rs | 4 +- crates/gpui/src/elements/tooltip.rs | 54 ++++++++------- crates/workspace/src/sidebar.rs | 73 ++++++++++----------- crates/workspace/src/workspace.rs | 19 ++++-- 6 files changed, 86 insertions(+), 72 deletions(-) diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index a21a9d98ab64c1e5f7b74e6716ed5e2808caaddb..9bf9d0fa0b73448f9e17e94aefc21f930b0bd947 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -350,6 +350,8 @@ impl ContactsPanel { is_selected: bool, cx: &mut RenderContext, ) -> ElementBox { + enum ToggleOnline {} + let project = &contact.projects[project_index]; let project_id = project.id; let is_host = Some(contact.user.id) == current_user_id; @@ -445,7 +447,7 @@ impl ContactsPanel { project: Some(open_project.clone()), }) }) - .with_tooltip( + .with_tooltip::( project_id as usize, "Take project offline".to_string(), None, @@ -565,7 +567,7 @@ impl ContactsPanel { project: Some(project.clone()), }) }) - .with_tooltip( + .with_tooltip::( project_id, "Take project online".to_string(), None, diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 7311141074a23b52ac1da0e0c8938077e3dd2250..c3d6614f23fabd88f1c3f23e814a43eccc1b3b3e 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -883,7 +883,7 @@ impl EditorElement { }) .with_cursor_style(CursorStyle::PointingHand) .on_click(move |_, _, cx| cx.dispatch_action(jump_action.clone())) - .with_tooltip( + .with_tooltip::( *key, "Jump to Buffer".to_string(), Some(Box::new(crate::OpenExcerpts)), diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index d2d254d93eb1d7da3949d60bbfdc011b7fa65293..35703b8a1fb945deabef035f8f3cc2b196dd61e8 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -157,7 +157,7 @@ pub trait Element { FlexItem::new(self.boxed()).float() } - fn with_tooltip( + fn with_tooltip( self, id: usize, text: String, @@ -168,7 +168,7 @@ pub trait Element { where Self: 'static + Sized, { - Tooltip::new(id, text, action, style, self.boxed(), cx) + Tooltip::new::(id, text, action, style, self.boxed(), cx) } } diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index a7800a28f62335caaa826fc91d7d9d24407b7bcf..9a65b2661d71c216a50432605138336a35bb67db 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -49,7 +49,7 @@ pub struct KeystrokeStyle { } impl Tooltip { - pub fn new( + pub fn new( id: usize, text: String, action: Option>, @@ -57,7 +57,10 @@ impl Tooltip { child: ElementBox, cx: &mut RenderContext, ) -> Self { - let state_handle = cx.element_state::>(id); + struct ElementState(Tag); + struct MouseEventHandlerState(Tag); + + let state_handle = cx.element_state::, Rc>(id); let state = state_handle.read(cx).clone(); let tooltip = if state.visible.get() { let mut collapsed_tooltip = Self::render_tooltip( @@ -86,33 +89,34 @@ impl Tooltip { } else { None }; - let child = MouseEventHandler::new::(id, cx, |_, _| child) - .on_hover(move |position, hover, cx| { - let window_id = cx.window_id(); - if let Some(view_id) = cx.view_id() { - if hover { - if !state.visible.get() { - state.position.set(position); + let child = + MouseEventHandler::new::, _, _>(id, cx, |_, _| child) + .on_hover(move |position, hover, cx| { + let window_id = cx.window_id(); + if let Some(view_id) = cx.view_id() { + if hover { + if !state.visible.get() { + state.position.set(position); - let mut debounce = state.debounce.borrow_mut(); - if debounce.is_none() { - *debounce = Some(cx.spawn({ - let state = state.clone(); - |mut cx| async move { - cx.background().timer(DEBOUNCE_TIMEOUT).await; - state.visible.set(true); - cx.update(|cx| cx.notify_view(window_id, view_id)); - } - })); + let mut debounce = state.debounce.borrow_mut(); + if debounce.is_none() { + *debounce = Some(cx.spawn({ + let state = state.clone(); + |mut cx| async move { + cx.background().timer(DEBOUNCE_TIMEOUT).await; + state.visible.set(true); + cx.update(|cx| cx.notify_view(window_id, view_id)); + } + })); + } } + } else { + state.visible.set(false); + state.debounce.take(); } - } else { - state.visible.set(false); - state.debounce.take(); } - } - }) - .boxed(); + }) + .boxed(); Self { child, tooltip, diff --git a/crates/workspace/src/sidebar.rs b/crates/workspace/src/sidebar.rs index 0b8affa9cafde4f9da17a7f238381a940438eb31..0cfb7f7865232679873a7c924264465f903d8929 100644 --- a/crates/workspace/src/sidebar.rs +++ b/crates/workspace/src/sidebar.rs @@ -266,47 +266,44 @@ impl View for SidebarButtons { side, item_index: ix, }; - MouseEventHandler::new::(ix, cx, { - let action = action.clone(); - let tooltip_style = tooltip_style.clone(); - move |state, cx| { - let is_active = Some(ix) == active_ix; - let style = item_style.style_for(state, is_active); - Stack::new() - .with_child( - Svg::new(icon_path).with_color(style.icon_color).boxed(), - ) - .with_children(if !is_active && item_view.should_show_badge(cx) { - Some( - Empty::new() - .collapsed() - .contained() - .with_style(badge_style) - .aligned() - .bottom() - .right() - .boxed(), - ) - } else { - None - }) - .constrained() - .with_width(style.icon_size) - .with_height(style.icon_size) - .contained() - .with_style(style.container) - .with_tooltip( - ix, - tooltip, - Some(Box::new(action.clone())), - tooltip_style.clone(), - cx, + MouseEventHandler::new::(ix, cx, move |state, cx| { + let is_active = Some(ix) == active_ix; + let style = item_style.style_for(state, is_active); + Stack::new() + .with_child(Svg::new(icon_path).with_color(style.icon_color).boxed()) + .with_children(if !is_active && item_view.should_show_badge(cx) { + Some( + Empty::new() + .collapsed() + .contained() + .with_style(badge_style) + .aligned() + .bottom() + .right() + .boxed(), ) - .boxed() - } + } else { + None + }) + .constrained() + .with_width(style.icon_size) + .with_height(style.icon_size) + .contained() + .with_style(style.container) + .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(move |_, _, cx| cx.dispatch_action(action.clone())) + .on_click({ + let action = action.clone(); + move |_, _, cx| cx.dispatch_action(action.clone()) + }) + .with_tooltip::( + ix, + tooltip, + Some(Box::new(action)), + tooltip_style.clone(), + cx, + ) .boxed() }, )) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index aed1bf5b46aecdb4d619744b37b2d973d60be03a..63e1d60df6cf48862a59f026d0640cd7083fc9b8 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1788,7 +1788,7 @@ impl Workspace { Some(self.render_avatar( collaborator.user.avatar.clone()?, collaborator.replica_id, - Some(collaborator.peer_id), + Some((collaborator.peer_id, &collaborator.user.github_login)), theme, cx, )) @@ -1833,12 +1833,12 @@ impl Workspace { &self, avatar: Arc, replica_id: ReplicaId, - peer_id: Option, + peer: Option<(PeerId, &str)>, theme: &Theme, cx: &mut RenderContext, ) -> ElementBox { let replica_color = theme.editor.replica_selection_style(replica_id).cursor; - let is_followed = peer_id.map_or(false, |peer_id| { + let is_followed = peer.map_or(false, |(peer_id, _)| { self.follower_states_by_leader.contains_key(&peer_id) }); let mut avatar_style = theme.workspace.titlebar.avatar; @@ -1869,10 +1869,21 @@ impl Workspace { .with_margin_left(theme.workspace.titlebar.avatar_margin) .boxed(); - if let Some(peer_id) = peer_id { + if let Some((peer_id, peer_github_login)) = peer { MouseEventHandler::new::(replica_id.into(), cx, move |_, _| content) .with_cursor_style(CursorStyle::PointingHand) .on_click(move |_, _, cx| cx.dispatch_action(ToggleFollow(peer_id))) + .with_tooltip::( + peer_id.0 as usize, + if is_followed { + format!("Unfollow {}", peer_github_login) + } else { + format!("Follow {}", peer_github_login) + }, + Some(Box::new(FollowNextCollaborator)), + theme.tooltip.clone(), + cx, + ) .boxed() } else { content