diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index 2b931f7085..f48a78fb1d 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -2,11 +2,13 @@ use crate::face_pile::FacePile; use call::{ActiveCall, ParticipantLocation, Room}; use client::{proto::PeerId, Client, ParticipantIndex, User, UserStore}; use gpui::{ - actions, canvas, div, point, px, rems, AppContext, Div, Element, Hsla, InteractiveElement, - IntoElement, Model, ParentElement, Path, Render, Stateful, StatefulInteractiveElement, Styled, - Subscription, ViewContext, VisualContext, WeakView, WindowBounds, + actions, canvas, div, overlay, point, px, rems, AppContext, DismissEvent, Div, Element, + FocusableView, Hsla, InteractiveElement, IntoElement, Model, Overlay, ParentElement, Path, + Render, Stateful, StatefulInteractiveElement, Styled, Subscription, ViewContext, VisualContext, + WeakView, WindowBounds, }; use project::{Project, RepositoryEntry}; +use recent_projects::RecentProjects; use std::sync::Arc; use theme::{ActiveTheme, PlayerColors}; use ui::{ @@ -14,7 +16,7 @@ use ui::{ IconButton, IconElement, KeyBinding, Tooltip, }; use util::ResultExt; -use workspace::{notifications::NotifyResultExt, Workspace}; +use workspace::{notifications::NotifyResultExt, Workspace, WORKSPACE_DB}; const MAX_PROJECT_NAME_LENGTH: usize = 40; const MAX_BRANCH_NAME_LENGTH: usize = 40; @@ -49,7 +51,7 @@ pub struct CollabTitlebarItem { client: Arc, workspace: WeakView, //branch_popover: Option>, - //project_popover: Option>, + project_popover: Option, //user_menu: ViewHandle, _subscriptions: Vec, } @@ -328,7 +330,7 @@ impl CollabTitlebarItem { // menu // }), // branch_popover: None, - // project_popover: None, + project_popover: None, _subscriptions: subscriptions, } } @@ -366,11 +368,27 @@ impl CollabTitlebarItem { let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH); - div().border().border_color(gpui::red()).child( - Button::new("project_name_trigger", name) - .style(ButtonStyle::Subtle) - .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), - ) + div() + .border() + .border_color(gpui::red()) + .child( + Button::new("project_name_trigger", name) + .style(ButtonStyle::Subtle) + .tooltip(move |cx| Tooltip::text("Recent Projects", cx)) + .on_click(cx.listener(|this, _, cx| { + this.toggle_project_menu(&ToggleProjectMenu, cx); + })), + ) + .children(self.project_popover.as_ref().map(|popover| { + overlay().child( + div() + .min_w_56() + .on_mouse_down_out(cx.listener_for(&popover.picker, |picker, _, cx| { + picker.cancel(&Default::default(), cx) + })) + .child(popover.picker.clone()), + ) + })) } pub fn render_project_branch(&self, cx: &mut ViewContext) -> Option { @@ -611,43 +629,40 @@ impl CollabTitlebarItem { // cx.notify(); // } - // pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext) { - // let workspace = self.workspace.clone(); - // if self.project_popover.take().is_none() { - // cx.spawn(|this, mut cx| async move { - // let workspaces = WORKSPACE_DB - // .recent_workspaces_on_disk() - // .await - // .unwrap_or_default() - // .into_iter() - // .map(|(_, location)| location) - // .collect(); + pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext) { + let workspace = self.workspace.clone(); + if self.project_popover.take().is_none() { + cx.spawn(|this, mut cx| async move { + let workspaces = WORKSPACE_DB + .recent_workspaces_on_disk() + .await + .unwrap_or_default() + .into_iter() + .map(|(_, location)| location) + .collect(); - // let workspace = workspace.clone(); - // this.update(&mut cx, move |this, cx| { - // let view = cx.add_view(|cx| build_recent_projects(workspace, workspaces, cx)); + let workspace = workspace.clone(); + this.update(&mut cx, move |this, cx| { + let view = RecentProjects::open_popover(workspace, workspaces, cx); - // cx.subscribe(&view, |this, _, event, cx| { - // match event { - // PickerEvent::Dismiss => { - // this.project_popover = None; - // } - // } - - // cx.notify(); - // }) - // .detach(); - // cx.focus(&view); - // this.branch_popover.take(); - // this.project_popover = Some(view); - // cx.notify(); - // }) - // .log_err(); - // }) - // .detach(); - // } - // cx.notify(); - // } + cx.subscribe(&view.picker, |this, _, _: &DismissEvent, cx| { + this.project_popover = None; + cx.notify(); + }) + .detach(); + let focus_handle = view.focus_handle(cx); + cx.focus(&focus_handle); + // todo!() + //this.branch_popover.take(); + this.project_popover = Some(view); + cx.notify(); + }) + .log_err(); + }) + .detach(); + } + cx.notify(); + } // fn render_user_menu_button( // &self, diff --git a/crates/picker2/src/picker2.rs b/crates/picker2/src/picker2.rs index 98b6ce5ff0..db5eebff53 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -1,8 +1,8 @@ use editor::Editor; use gpui::{ - div, prelude::*, rems, uniform_list, AnyElement, AppContext, Div, FocusHandle, FocusableView, - MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle, View, ViewContext, - WindowContext, + div, prelude::*, rems, uniform_list, AnyElement, AppContext, DismissEvent, Div, EventEmitter, + FocusHandle, FocusableView, MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle, + View, ViewContext, WindowContext, }; use std::{cmp, sync::Arc}; use ui::{prelude::*, v_stack, Color, Divider, Label}; @@ -113,8 +113,9 @@ impl Picker { cx.notify(); } - fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext) { + pub fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext) { self.delegate.dismissed(cx); + cx.emit(DismissEvent); } fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { @@ -146,9 +147,15 @@ impl Picker { event: &editor::EditorEvent, cx: &mut ViewContext, ) { - if let editor::EditorEvent::BufferEdited = event { - let query = self.editor.read(cx).text(cx); - self.update_matches(query, cx); + match event { + editor::EditorEvent::BufferEdited => { + let query = self.editor.read(cx).text(cx); + self.update_matches(query, cx); + } + editor::EditorEvent::Blurred => { + self.cancel(&menu::Cancel, cx); + } + _ => {} } } @@ -189,6 +196,8 @@ impl Picker { } } +impl EventEmitter for Picker {} + impl Render for Picker { type Element = Div; diff --git a/crates/recent_projects2/src/recent_projects.rs b/crates/recent_projects2/src/recent_projects.rs index e014783687..dff6aa12cc 100644 --- a/crates/recent_projects2/src/recent_projects.rs +++ b/crates/recent_projects2/src/recent_projects.rs @@ -23,14 +23,15 @@ pub fn init(cx: &mut AppContext) { cx.observe_new_views(RecentProjects::register).detach(); } +#[derive(Clone)] pub struct RecentProjects { - picker: View>, + pub picker: View>, } impl ModalView for RecentProjects {} impl RecentProjects { - fn new(delegate: RecentProjectsDelegate, cx: &mut ViewContext) -> Self { + fn new(delegate: RecentProjectsDelegate, cx: &mut WindowContext<'_>) -> Self { Self { picker: cx.build_view(|cx| Picker::new(delegate, cx)), } @@ -86,6 +87,16 @@ impl RecentProjects { Ok(()) })) } + pub fn open_popover( + workspace: WeakView, + workspaces: Vec, + cx: &mut WindowContext<'_>, + ) -> Self { + Self::new( + RecentProjectsDelegate::new(workspace, workspaces, false), + cx, + ) + } } impl EventEmitter for RecentProjects {} @@ -127,7 +138,7 @@ impl RecentProjectsDelegate { } } } - +impl EventEmitter for RecentProjectsDelegate {} impl PickerDelegate for RecentProjectsDelegate { type ListItem = ListItem; @@ -202,11 +213,11 @@ impl PickerDelegate for RecentProjectsDelegate { .open_workspace_for_paths(workspace_location.paths().as_ref().clone(), cx) }) .detach_and_log_err(cx); - self.dismissed(cx); + cx.emit(DismissEvent); } } - fn dismissed(&mut self, _cx: &mut ViewContext>) {} + fn dismissed(&mut self, _: &mut ViewContext>) {} fn render_match( &self,