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