1use crate::{
2 contact_finder::{build_contact_finder, ContactFinder},
3 contact_list::ContactList,
4};
5use client::UserStore;
6use gpui::{
7 actions, elements::*, platform::MouseButton, AppContext, Entity, ModelHandle, View,
8 ViewContext, ViewHandle, WeakViewHandle,
9};
10use picker::PickerEvent;
11use project::Project;
12use settings::Settings;
13use workspace::Workspace;
14
15actions!(contacts_popover, [ToggleContactFinder]);
16
17pub fn init(cx: &mut AppContext) {
18 cx.add_action(ContactsPopover::toggle_contact_finder);
19}
20
21pub enum Event {
22 Dismissed,
23}
24
25enum Child {
26 ContactList(ViewHandle<ContactList>),
27 ContactFinder(ViewHandle<ContactFinder>),
28}
29
30pub struct ContactsPopover {
31 child: Child,
32 project: ModelHandle<Project>,
33 user_store: ModelHandle<UserStore>,
34 workspace: WeakViewHandle<Workspace>,
35 _subscription: Option<gpui::Subscription>,
36}
37
38impl ContactsPopover {
39 pub fn new(
40 project: ModelHandle<Project>,
41 user_store: ModelHandle<UserStore>,
42 workspace: WeakViewHandle<Workspace>,
43 cx: &mut ViewContext<Self>,
44 ) -> Self {
45 let mut this = Self {
46 child: Child::ContactList(cx.add_view(|cx| {
47 ContactList::new(project.clone(), user_store.clone(), workspace.clone(), cx)
48 })),
49 project,
50 user_store,
51 workspace,
52 _subscription: None,
53 };
54 this.show_contact_list(String::new(), cx);
55 this
56 }
57
58 fn toggle_contact_finder(&mut self, _: &ToggleContactFinder, cx: &mut ViewContext<Self>) {
59 match &self.child {
60 Child::ContactList(list) => self.show_contact_finder(list.read(cx).editor_text(cx), cx),
61 Child::ContactFinder(finder) => self.show_contact_list(finder.read(cx).query(cx), cx),
62 }
63 }
64
65 fn show_contact_finder(&mut self, editor_text: String, cx: &mut ViewContext<ContactsPopover>) {
66 let child = cx.add_view(|cx| {
67 let finder = build_contact_finder(self.user_store.clone(), cx);
68 finder.set_query(editor_text, cx);
69 finder
70 });
71 cx.focus(&child);
72 self._subscription = Some(cx.subscribe(&child, |_, _, event, cx| match event {
73 PickerEvent::Dismiss => cx.emit(Event::Dismissed),
74 }));
75 self.child = Child::ContactFinder(child);
76 cx.notify();
77 }
78
79 fn show_contact_list(&mut self, editor_text: String, cx: &mut ViewContext<ContactsPopover>) {
80 let child = cx.add_view(|cx| {
81 ContactList::new(
82 self.project.clone(),
83 self.user_store.clone(),
84 self.workspace.clone(),
85 cx,
86 )
87 .with_editor_text(editor_text, cx)
88 });
89 cx.focus(&child);
90 self._subscription = Some(cx.subscribe(&child, |this, _, event, cx| match event {
91 crate::contact_list::Event::Dismissed => cx.emit(Event::Dismissed),
92 crate::contact_list::Event::ToggleContactFinder => {
93 this.toggle_contact_finder(&Default::default(), cx)
94 }
95 }));
96 self.child = Child::ContactList(child);
97 cx.notify();
98 }
99}
100
101impl Entity for ContactsPopover {
102 type Event = Event;
103}
104
105impl View for ContactsPopover {
106 fn ui_name() -> &'static str {
107 "ContactsPopover"
108 }
109
110 fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
111 let theme = cx.global::<Settings>().theme.clone();
112 let child = match &self.child {
113 Child::ContactList(child) => ChildView::new(child, cx),
114 Child::ContactFinder(child) => ChildView::new(child, cx),
115 };
116
117 MouseEventHandler::<ContactsPopover, Self>::new(0, cx, |_, _| {
118 Flex::column()
119 .with_child(child.flex(1., true))
120 .contained()
121 .with_style(theme.contacts_popover.container)
122 .constrained()
123 .with_width(theme.contacts_popover.width)
124 .with_height(theme.contacts_popover.height)
125 })
126 .on_down_out(MouseButton::Left, move |_, _, cx| cx.emit(Event::Dismissed))
127 .into_any()
128 }
129
130 fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext<Self>) {
131 if cx.is_self_focused() {
132 match &self.child {
133 Child::ContactList(child) => cx.focus(child),
134 Child::ContactFinder(child) => cx.focus(child),
135 }
136 }
137 }
138}