collab_ui: Wire up project picker

Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
Piotr Osiewicz 2023-12-13 17:56:49 +01:00
parent 2a714d6dd8
commit a71365a1d3
3 changed files with 93 additions and 58 deletions

View file

@ -2,11 +2,13 @@ use crate::face_pile::FacePile;
use call::{ActiveCall, ParticipantLocation, Room}; use call::{ActiveCall, ParticipantLocation, Room};
use client::{proto::PeerId, Client, ParticipantIndex, User, UserStore}; use client::{proto::PeerId, Client, ParticipantIndex, User, UserStore};
use gpui::{ use gpui::{
actions, canvas, div, point, px, rems, AppContext, Div, Element, Hsla, InteractiveElement, actions, canvas, div, overlay, point, px, rems, AppContext, DismissEvent, Div, Element,
IntoElement, Model, ParentElement, Path, Render, Stateful, StatefulInteractiveElement, Styled, FocusableView, Hsla, InteractiveElement, IntoElement, Model, Overlay, ParentElement, Path,
Subscription, ViewContext, VisualContext, WeakView, WindowBounds, Render, Stateful, StatefulInteractiveElement, Styled, Subscription, ViewContext, VisualContext,
WeakView, WindowBounds,
}; };
use project::{Project, RepositoryEntry}; use project::{Project, RepositoryEntry};
use recent_projects::RecentProjects;
use std::sync::Arc; use std::sync::Arc;
use theme::{ActiveTheme, PlayerColors}; use theme::{ActiveTheme, PlayerColors};
use ui::{ use ui::{
@ -14,7 +16,7 @@ use ui::{
IconButton, IconElement, KeyBinding, Tooltip, IconButton, IconElement, KeyBinding, Tooltip,
}; };
use util::ResultExt; use util::ResultExt;
use workspace::{notifications::NotifyResultExt, Workspace}; use workspace::{notifications::NotifyResultExt, Workspace, WORKSPACE_DB};
const MAX_PROJECT_NAME_LENGTH: usize = 40; const MAX_PROJECT_NAME_LENGTH: usize = 40;
const MAX_BRANCH_NAME_LENGTH: usize = 40; const MAX_BRANCH_NAME_LENGTH: usize = 40;
@ -49,7 +51,7 @@ pub struct CollabTitlebarItem {
client: Arc<Client>, client: Arc<Client>,
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
//branch_popover: Option<ViewHandle<BranchList>>, //branch_popover: Option<ViewHandle<BranchList>>,
//project_popover: Option<ViewHandle<recent_projects::RecentProjects>>, project_popover: Option<recent_projects::RecentProjects>,
//user_menu: ViewHandle<ContextMenu>, //user_menu: ViewHandle<ContextMenu>,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
@ -328,7 +330,7 @@ impl CollabTitlebarItem {
// menu // menu
// }), // }),
// branch_popover: None, // branch_popover: None,
// project_popover: None, project_popover: None,
_subscriptions: subscriptions, _subscriptions: subscriptions,
} }
} }
@ -366,11 +368,27 @@ impl CollabTitlebarItem {
let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH); let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH);
div().border().border_color(gpui::red()).child( div()
.border()
.border_color(gpui::red())
.child(
Button::new("project_name_trigger", name) Button::new("project_name_trigger", name)
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.tooltip(move |cx| Tooltip::text("Recent Projects", cx)), .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<Self>) -> Option<impl Element> { pub fn render_project_branch(&self, cx: &mut ViewContext<Self>) -> Option<impl Element> {
@ -611,43 +629,40 @@ impl CollabTitlebarItem {
// cx.notify(); // cx.notify();
// } // }
// pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext<Self>) { pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext<Self>) {
// let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
// if self.project_popover.take().is_none() { if self.project_popover.take().is_none() {
// cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
// let workspaces = WORKSPACE_DB let workspaces = WORKSPACE_DB
// .recent_workspaces_on_disk() .recent_workspaces_on_disk()
// .await .await
// .unwrap_or_default() .unwrap_or_default()
// .into_iter() .into_iter()
// .map(|(_, location)| location) .map(|(_, location)| location)
// .collect(); .collect();
// let workspace = workspace.clone(); let workspace = workspace.clone();
// this.update(&mut cx, move |this, cx| { this.update(&mut cx, move |this, cx| {
// let view = cx.add_view(|cx| build_recent_projects(workspace, workspaces, cx)); let view = RecentProjects::open_popover(workspace, workspaces, cx);
// cx.subscribe(&view, |this, _, event, cx| { cx.subscribe(&view.picker, |this, _, _: &DismissEvent, cx| {
// match event { this.project_popover = None;
// PickerEvent::Dismiss => { cx.notify();
// this.project_popover = None; })
// } .detach();
// } let focus_handle = view.focus_handle(cx);
cx.focus(&focus_handle);
// cx.notify(); // todo!()
// })
// .detach();
// cx.focus(&view);
//this.branch_popover.take(); //this.branch_popover.take();
// this.project_popover = Some(view); this.project_popover = Some(view);
// cx.notify(); cx.notify();
// }) })
// .log_err(); .log_err();
// }) })
// .detach(); .detach();
// } }
// cx.notify(); cx.notify();
// } }
// fn render_user_menu_button( // fn render_user_menu_button(
// &self, // &self,

View file

@ -1,8 +1,8 @@
use editor::Editor; use editor::Editor;
use gpui::{ use gpui::{
div, prelude::*, rems, uniform_list, AnyElement, AppContext, Div, FocusHandle, FocusableView, div, prelude::*, rems, uniform_list, AnyElement, AppContext, DismissEvent, Div, EventEmitter,
MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle, View, ViewContext, FocusHandle, FocusableView, MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle,
WindowContext, View, ViewContext, WindowContext,
}; };
use std::{cmp, sync::Arc}; use std::{cmp, sync::Arc};
use ui::{prelude::*, v_stack, Color, Divider, Label}; use ui::{prelude::*, v_stack, Color, Divider, Label};
@ -113,8 +113,9 @@ impl<D: PickerDelegate> Picker<D> {
cx.notify(); cx.notify();
} }
fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) { pub fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
self.delegate.dismissed(cx); self.delegate.dismissed(cx);
cx.emit(DismissEvent);
} }
fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) { fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
@ -146,10 +147,16 @@ impl<D: PickerDelegate> Picker<D> {
event: &editor::EditorEvent, event: &editor::EditorEvent,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
if let editor::EditorEvent::BufferEdited = event { match event {
editor::EditorEvent::BufferEdited => {
let query = self.editor.read(cx).text(cx); let query = self.editor.read(cx).text(cx);
self.update_matches(query, cx); self.update_matches(query, cx);
} }
editor::EditorEvent::Blurred => {
self.cancel(&menu::Cancel, cx);
}
_ => {}
}
} }
pub fn refresh(&mut self, cx: &mut ViewContext<Self>) { pub fn refresh(&mut self, cx: &mut ViewContext<Self>) {
@ -189,6 +196,8 @@ impl<D: PickerDelegate> Picker<D> {
} }
} }
impl<D: PickerDelegate> EventEmitter<DismissEvent> for Picker<D> {}
impl<D: PickerDelegate> Render for Picker<D> { impl<D: PickerDelegate> Render for Picker<D> {
type Element = Div; type Element = Div;

View file

@ -23,14 +23,15 @@ pub fn init(cx: &mut AppContext) {
cx.observe_new_views(RecentProjects::register).detach(); cx.observe_new_views(RecentProjects::register).detach();
} }
#[derive(Clone)]
pub struct RecentProjects { pub struct RecentProjects {
picker: View<Picker<RecentProjectsDelegate>>, pub picker: View<Picker<RecentProjectsDelegate>>,
} }
impl ModalView for RecentProjects {} impl ModalView for RecentProjects {}
impl RecentProjects { impl RecentProjects {
fn new(delegate: RecentProjectsDelegate, cx: &mut ViewContext<Self>) -> Self { fn new(delegate: RecentProjectsDelegate, cx: &mut WindowContext<'_>) -> Self {
Self { Self {
picker: cx.build_view(|cx| Picker::new(delegate, cx)), picker: cx.build_view(|cx| Picker::new(delegate, cx)),
} }
@ -86,6 +87,16 @@ impl RecentProjects {
Ok(()) Ok(())
})) }))
} }
pub fn open_popover(
workspace: WeakView<Workspace>,
workspaces: Vec<WorkspaceLocation>,
cx: &mut WindowContext<'_>,
) -> Self {
Self::new(
RecentProjectsDelegate::new(workspace, workspaces, false),
cx,
)
}
} }
impl EventEmitter<DismissEvent> for RecentProjects {} impl EventEmitter<DismissEvent> for RecentProjects {}
@ -127,7 +138,7 @@ impl RecentProjectsDelegate {
} }
} }
} }
impl EventEmitter<DismissEvent> for RecentProjectsDelegate {}
impl PickerDelegate for RecentProjectsDelegate { impl PickerDelegate for RecentProjectsDelegate {
type ListItem = ListItem; type ListItem = ListItem;
@ -202,11 +213,11 @@ impl PickerDelegate for RecentProjectsDelegate {
.open_workspace_for_paths(workspace_location.paths().as_ref().clone(), cx) .open_workspace_for_paths(workspace_location.paths().as_ref().clone(), cx)
}) })
.detach_and_log_err(cx); .detach_and_log_err(cx);
self.dismissed(cx); cx.emit(DismissEvent);
} }
} }
fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {} fn dismissed(&mut self, _: &mut ViewContext<Picker<Self>>) {}
fn render_match( fn render_match(
&self, &self,