Detailed changes
@@ -17,10 +17,14 @@ use std::{ops::Range, sync::Arc};
use theme::Theme;
use workspace::{FollowNextCollaborator, ToggleFollow, Workspace};
-actions!(contacts_titlebar_item, [ToggleContactsPopover]);
+actions!(
+ contacts_titlebar_item,
+ [ToggleContactsPopover, ShareProject]
+);
pub fn init(cx: &mut MutableAppContext) {
cx.add_action(CollabTitlebarItem::toggle_contacts_popover);
+ cx.add_action(CollabTitlebarItem::share_project);
}
pub struct CollabTitlebarItem {
@@ -47,12 +51,20 @@ impl View for CollabTitlebarItem {
};
let theme = cx.global::<Settings>().theme.clone();
- Flex::row()
- .with_children(self.render_toggle_contacts_button(&workspace, &theme, cx))
- .with_children(self.render_collaborators(&workspace, &theme, cx))
- .with_children(self.render_current_user(&workspace, &theme, cx))
- .with_children(self.render_connection_status(&workspace, cx))
- .boxed()
+ let project = workspace.read(cx).project().read(cx);
+
+ let mut container = Flex::row();
+ if workspace.read(cx).client().status().borrow().is_connected() {
+ if project.is_shared() || ActiveCall::global(cx).read(cx).room().is_none() {
+ container.add_child(self.render_toggle_contacts_button(&theme, cx));
+ } else {
+ container.add_child(self.render_share_button(&theme, cx));
+ }
+ }
+ container.add_children(self.render_collaborators(&workspace, &theme, cx));
+ container.add_children(self.render_current_user(&workspace, &theme, cx));
+ container.add_children(self.render_connection_status(&workspace, cx));
+ container.boxed()
}
}
@@ -81,6 +93,18 @@ impl CollabTitlebarItem {
cx.notify();
}
+ fn share_project(&mut self, _: &ShareProject, cx: &mut ViewContext<Self>) {
+ if let Some(workspace) = self.workspace.upgrade(cx) {
+ if let Some(room) = ActiveCall::global(cx).read(cx).room() {
+ let room_id = room.read(cx).id();
+ let project = workspace.read(cx).project().clone();
+ project
+ .update(cx, |project, cx| project.share(room_id, cx))
+ .detach_and_log_err(cx);
+ }
+ }
+ }
+
fn toggle_contacts_popover(&mut self, _: &ToggleContactsPopover, cx: &mut ViewContext<Self>) {
match self.contacts_popover.take() {
Some(_) => {}
@@ -108,58 +132,72 @@ impl CollabTitlebarItem {
fn render_toggle_contacts_button(
&self,
- workspace: &ViewHandle<Workspace>,
theme: &Theme,
cx: &mut RenderContext<Self>,
- ) -> Option<ElementBox> {
- if !workspace.read(cx).client().status().borrow().is_connected() {
- return None;
- }
-
+ ) -> ElementBox {
let titlebar = &theme.workspace.titlebar;
-
- Some(
- Stack::new()
- .with_child(
- MouseEventHandler::<ToggleContactsPopover>::new(0, cx, |state, _| {
- let style = titlebar
- .toggle_contacts_button
- .style_for(state, self.contacts_popover.is_some());
- Svg::new("icons/plus_8.svg")
- .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)
- .boxed()
- })
- .with_cursor_style(CursorStyle::PointingHand)
- .on_click(MouseButton::Left, |_, cx| {
- cx.dispatch_action(ToggleContactsPopover);
- })
- .aligned()
- .boxed(),
- )
- .with_children(self.contacts_popover.as_ref().map(|popover| {
- Overlay::new(
- ChildView::new(popover)
- .contained()
- .with_margin_top(titlebar.height)
- .with_margin_right(
- -titlebar.toggle_contacts_button.default.button_width,
- )
- .boxed(),
- )
- .with_fit_mode(OverlayFitMode::SwitchAnchor)
- .with_anchor_corner(AnchorCorner::BottomLeft)
- .boxed()
- }))
+ Stack::new()
+ .with_child(
+ MouseEventHandler::<ToggleContactsPopover>::new(0, cx, |state, _| {
+ let style = titlebar
+ .toggle_contacts_button
+ .style_for(state, self.contacts_popover.is_some());
+ Svg::new("icons/plus_8.svg")
+ .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)
+ .boxed()
+ })
+ .with_cursor_style(CursorStyle::PointingHand)
+ .on_click(MouseButton::Left, |_, cx| {
+ cx.dispatch_action(ToggleContactsPopover);
+ })
+ .aligned()
.boxed(),
+ )
+ .with_children(self.contacts_popover.as_ref().map(|popover| {
+ Overlay::new(
+ ChildView::new(popover)
+ .contained()
+ .with_margin_top(titlebar.height)
+ .with_margin_right(-titlebar.toggle_contacts_button.default.button_width)
+ .boxed(),
+ )
+ .with_fit_mode(OverlayFitMode::SwitchAnchor)
+ .with_anchor_corner(AnchorCorner::BottomLeft)
+ .boxed()
+ }))
+ .boxed()
+ }
+
+ fn render_share_button(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
+ enum Share {}
+
+ let titlebar = &theme.workspace.titlebar;
+ MouseEventHandler::<Share>::new(0, cx, |state, _| {
+ let style = titlebar.share_button.style_for(state, false);
+ Label::new("Share".into(), style.text.clone())
+ .contained()
+ .with_style(style.container)
+ .boxed()
+ })
+ .with_cursor_style(CursorStyle::PointingHand)
+ .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(ShareProject))
+ .with_tooltip::<Share, _>(
+ 0,
+ "Share project with call participants".into(),
+ None,
+ theme.tooltip.clone(),
+ cx,
)
+ .aligned()
+ .boxed()
}
fn render_collaborators(
@@ -479,40 +479,49 @@ impl ContactsPopover {
is_selected: bool,
cx: &mut RenderContext<Self>,
) -> ElementBox {
+ let online = contact.online;
let user_id = contact.user.id;
- MouseEventHandler::<Contact>::new(contact.user.id as usize, cx, |_, _| {
- Flex::row()
- .with_children(contact.user.avatar.clone().map(|avatar| {
- Image::new(avatar)
- .with_style(theme.contact_avatar)
+ let mut element =
+ MouseEventHandler::<Contact>::new(contact.user.id as usize, cx, |_, _| {
+ Flex::row()
+ .with_children(contact.user.avatar.clone().map(|avatar| {
+ Image::new(avatar)
+ .with_style(theme.contact_avatar)
+ .aligned()
+ .left()
+ .boxed()
+ }))
+ .with_child(
+ Label::new(
+ contact.user.github_login.clone(),
+ theme.contact_username.text.clone(),
+ )
+ .contained()
+ .with_style(theme.contact_username.container)
.aligned()
.left()
- .boxed()
- }))
- .with_child(
- Label::new(
- contact.user.github_login.clone(),
- theme.contact_username.text.clone(),
+ .flex(1., true)
+ .boxed(),
)
+ .constrained()
+ .with_height(theme.row_height)
.contained()
- .with_style(theme.contact_username.container)
- .aligned()
- .left()
- .flex(1., true)
- .boxed(),
- )
- .constrained()
- .with_height(theme.row_height)
- .contained()
- .with_style(*theme.contact_row.style_for(Default::default(), is_selected))
- .boxed()
- })
- .on_click(MouseButton::Left, move |_, cx| {
- cx.dispatch_action(Call {
- recipient_user_id: user_id,
+ .with_style(*theme.contact_row.style_for(Default::default(), is_selected))
+ .boxed()
})
- })
- .boxed()
+ .on_click(MouseButton::Left, move |_, cx| {
+ if online {
+ cx.dispatch_action(Call {
+ recipient_user_id: user_id,
+ });
+ }
+ });
+
+ if online {
+ element = element.with_cursor_style(CursorStyle::PointingHand);
+ }
+
+ element.boxed()
}
fn render_contact_request(
@@ -74,6 +74,7 @@ pub struct Titlebar {
pub inactive_avatar: ImageStyle,
pub sign_in_prompt: Interactive<ContainedText>,
pub outdated_warning: ContainedText,
+ pub share_button: Interactive<ContainedText>,
pub toggle_contacts_button: Interactive<IconButton>,
pub contacts_popover: AddParticipantPopover,
}
@@ -17,6 +17,26 @@ export function workspaceBackground(theme: Theme) {
export default function workspace(theme: Theme) {
const titlebarPadding = 6;
+ const titlebarButton = {
+ background: backgroundColor(theme, 100),
+ border: border(theme, "secondary"),
+ cornerRadius: 6,
+ margin: {
+ top: 1,
+ },
+ padding: {
+ top: 1,
+ bottom: 1,
+ left: 7,
+ right: 7,
+ },
+ ...text(theme, "sans", "secondary", { size: "xs" }),
+ hover: {
+ ...text(theme, "sans", "active", { size: "xs" }),
+ background: backgroundColor(theme, "on300", "hovered"),
+ border: border(theme, "primary"),
+ },
+ };
return {
background: backgroundColor(theme, 300),
@@ -81,24 +101,7 @@ export default function workspace(theme: Theme) {
},
border: border(theme, "primary", { bottom: true, overlay: true }),
signInPrompt: {
- background: backgroundColor(theme, 100),
- border: border(theme, "secondary"),
- cornerRadius: 6,
- margin: {
- top: 1,
- },
- padding: {
- top: 1,
- bottom: 1,
- left: 7,
- right: 7,
- },
- ...text(theme, "sans", "secondary", { size: "xs" }),
- hover: {
- ...text(theme, "sans", "active", { size: "xs" }),
- background: backgroundColor(theme, "on300", "hovered"),
- border: border(theme, "primary"),
- },
+ ...titlebarButton
},
offlineIcon: {
color: iconColor(theme, "secondary"),
@@ -137,6 +140,9 @@ export default function workspace(theme: Theme) {
color: iconColor(theme, "active"),
},
},
+ shareButton: {
+ ...titlebarButton
+ },
contactsPopover: {
background: backgroundColor(theme, 300, "base"),
cornerRadius: 6,