From 888d3b3fd620722a44483222cd4c3201153b15a4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:03:01 +0200 Subject: [PATCH] Project dropdown menu --- Cargo.lock | 2 + crates/collab_ui/Cargo.toml | 2 + crates/collab_ui/src/collab_titlebar_item.rs | 79 +++++++++++++++++-- crates/recent_projects/Cargo.toml | 1 + crates/recent_projects/src/recent_projects.rs | 21 ++++- 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a59332520b..d16248c85a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1415,6 +1415,7 @@ dependencies = [ "picker", "postage", "project", + "recent_projects", "serde", "serde_derive", "settings", @@ -5376,6 +5377,7 @@ version = "0.1.0" dependencies = [ "db", "editor", + "futures 0.3.28", "fuzzy", "gpui", "language", diff --git a/crates/collab_ui/Cargo.toml b/crates/collab_ui/Cargo.toml index ee410ccba7..f81885c07a 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -35,6 +35,7 @@ gpui = { path = "../gpui" } menu = { path = "../menu" } picker = { path = "../picker" } project = { path = "../project" } +recent_projects = {path = "../recent_projects"} settings = { path = "../settings" } theme = { path = "../theme" } theme_selector = { path = "../theme_selector" } @@ -42,6 +43,7 @@ util = { path = "../util" } workspace = { path = "../workspace" } zed-actions = {path = "../zed-actions"} + anyhow.workspace = true futures.workspace = true log.workspace = true diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 5bef89d1ee..8dccf2a71a 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -23,6 +23,7 @@ use gpui::{ }; use picker::PickerEvent; use project::{Project, RepositoryEntry}; +use recent_projects::{build_recent_projects, RecentProjects}; use std::{ops::Range, sync::Arc}; use theme::{AvatarStyle, Theme}; use util::ResultExt; @@ -37,6 +38,7 @@ actions!( ToggleContactsMenu, ToggleUserMenu, ToggleVcsMenu, + ToggleProjectMenu, SwitchBranch, ShareProject, UnshareProject, @@ -49,6 +51,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(CollabTitlebarItem::unshare_project); cx.add_action(CollabTitlebarItem::toggle_user_menu); cx.add_action(CollabTitlebarItem::toggle_vcs_menu); + cx.add_action(CollabTitlebarItem::toggle_project_menu); } pub struct CollabTitlebarItem { @@ -58,6 +61,7 @@ pub struct CollabTitlebarItem { workspace: WeakViewHandle, contacts_popover: Option>, branch_popover: Option>, + project_popover: Option>, user_menu: ViewHandle, _subscriptions: Vec, } @@ -191,6 +195,7 @@ impl CollabTitlebarItem { menu }), branch_popover: None, + project_popover: None, _subscriptions: subscriptions, } } @@ -233,14 +238,22 @@ impl CollabTitlebarItem { }; let highlights = (0..name.len()).into_iter().collect(); let mut ret = Flex::row().with_child( - Stack::new().with_child( - Label::new(name, style.clone()) - .with_highlights(highlights) - .contained() - .aligned() - .left() - .into_any_named("title-project-name"), - ), + Stack::new() + .with_child( + MouseEventHandler::::new(0, cx, |_, _| { + Label::new(name, style.clone()) + .with_highlights(highlights) + .contained() + .aligned() + .left() + .into_any_named("title-project-name") + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, this, cx| { + this.toggle_project_menu(&Default::default(), cx) + }), + ) + .with_children(self.render_project_popover_host(&theme.titlebar, cx)), ); if let Some(git_branch) = branch_prepended { ret = ret.with_child( @@ -382,6 +395,36 @@ impl CollabTitlebarItem { .into_any() }) } + fn render_project_popover_host<'a>( + &'a self, + _theme: &'a theme::Titlebar, + cx: &'a mut ViewContext, + ) -> Option> { + self.project_popover.as_ref().map(|child| { + let theme = theme::current(cx).clone(); + let child = ChildView::new(child, cx); + let child = MouseEventHandler::::new(0, cx, |_, _| { + Flex::column() + .with_child(child.flex(1., true)) + .contained() + .constrained() + .with_width(theme.contacts_popover.width) + .with_height(theme.contacts_popover.height) + }) + .on_click(MouseButton::Left, |_, _, _| {}) + .on_down_out(MouseButton::Left, move |_, _, cx| cx.emit(())) + .into_any(); + + Overlay::new(child) + .with_fit_mode(OverlayFitMode::SwitchAnchor) + .with_anchor_corner(AnchorCorner::TopLeft) + .with_z_index(999) + .aligned() + .bottom() + .left() + .into_any() + }) + } pub fn toggle_vcs_menu(&mut self, _: &ToggleVcsMenu, cx: &mut ViewContext) { if self.branch_popover.take().is_none() { if let Some(workspace) = self.workspace.upgrade(cx) { @@ -402,6 +445,26 @@ impl CollabTitlebarItem { cx.notify(); } + + pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext) { + log::error!("Toggling project menu"); + if self.project_popover.take().is_none() { + let view = cx.add_view(|cx| build_recent_projects(self.workspace.clone(), cx)); + cx.subscribe(&view, |this, _, event, cx| { + match event { + PickerEvent::Dismiss => { + this.project_popover = None; + } + } + + cx.notify(); + }) + .detach(); + self.project_popover = Some(view); + } + + cx.notify(); + } fn render_toggle_contacts_button( &self, theme: &Theme, diff --git a/crates/recent_projects/Cargo.toml b/crates/recent_projects/Cargo.toml index 14f8853c9c..51774e8feb 100644 --- a/crates/recent_projects/Cargo.toml +++ b/crates/recent_projects/Cargo.toml @@ -21,6 +21,7 @@ util = { path = "../util"} theme = { path = "../theme" } workspace = { path = "../workspace" } +futures.workspace = true ordered-float.workspace = true postage.workspace = true smol.workspace = true diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index b13f72da0b..ed901a7da8 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -64,9 +64,26 @@ fn toggle( })) } -type RecentProjects = Picker; +pub fn build_recent_projects( + workspace: WeakViewHandle, + cx: &mut ViewContext, +) -> RecentProjects { + let workspaces = futures::executor::block_on(async { + WORKSPACE_DB + .recent_workspaces_on_disk() + .await + .unwrap_or_default() + .into_iter() + .map(|(_, location)| location) + .collect() + }); + Picker::new(RecentProjectsDelegate::new(workspace, workspaces), cx) + .with_theme(|theme| theme.picker.clone()) +} -struct RecentProjectsDelegate { +pub type RecentProjects = Picker; + +pub struct RecentProjectsDelegate { workspace: WeakViewHandle, workspace_locations: Vec, selected_match_index: usize,