Add tooltip to follow collaborators

This commit is contained in:
Antonio Scandurra 2022-06-15 17:01:48 +02:00
parent 8a146e49ca
commit 516bd13474
6 changed files with 86 additions and 72 deletions

View file

@ -350,6 +350,8 @@ impl ContactsPanel {
is_selected: bool,
cx: &mut RenderContext<Self>,
) -> 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::<ToggleOnline, _>(
project_id as usize,
"Take project offline".to_string(),
None,
@ -565,7 +567,7 @@ impl ContactsPanel {
project: Some(project.clone()),
})
})
.with_tooltip(
.with_tooltip::<ToggleOnline, _>(
project_id,
"Take project online".to_string(),
None,

View file

@ -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::<JumpIcon, _>(
*key,
"Jump to Buffer".to_string(),
Some(Box::new(crate::OpenExcerpts)),

View file

@ -157,7 +157,7 @@ pub trait Element {
FlexItem::new(self.boxed()).float()
}
fn with_tooltip<T: View>(
fn with_tooltip<Tag: 'static, T: View>(
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::<Tag, T>(id, text, action, style, self.boxed(), cx)
}
}

View file

@ -49,7 +49,7 @@ pub struct KeystrokeStyle {
}
impl Tooltip {
pub fn new<T: View>(
pub fn new<Tag: 'static, T: View>(
id: usize,
text: String,
action: Option<Box<dyn Action>>,
@ -57,7 +57,10 @@ impl Tooltip {
child: ElementBox,
cx: &mut RenderContext<T>,
) -> Self {
let state_handle = cx.element_state::<TooltipState, Rc<TooltipState>>(id);
struct ElementState<Tag>(Tag);
struct MouseEventHandlerState<Tag>(Tag);
let state_handle = cx.element_state::<ElementState<Tag>, Rc<TooltipState>>(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::<Self, _, _>(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::<MouseEventHandlerState<Tag>, _, _>(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,

View file

@ -266,47 +266,44 @@ impl View for SidebarButtons {
side,
item_index: ix,
};
MouseEventHandler::new::<Self, _, _>(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(),
MouseEventHandler::new::<Self, _, _>(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(),
)
.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,
)
.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::<Self, _>(
ix,
tooltip,
Some(Box::new(action)),
tooltip_style.clone(),
cx,
)
.boxed()
},
))

View file

@ -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<ImageData>,
replica_id: ReplicaId,
peer_id: Option<PeerId>,
peer: Option<(PeerId, &str)>,
theme: &Theme,
cx: &mut RenderContext<Self>,
) -> 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::<ToggleFollow, _, _>(replica_id.into(), cx, move |_, _| content)
.with_cursor_style(CursorStyle::PointingHand)
.on_click(move |_, _, cx| cx.dispatch_action(ToggleFollow(peer_id)))
.with_tooltip::<ToggleFollow, _>(
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