1use crate::{contact_finder::ContactFinder, contact_list::ContactList, ToggleContactsMenu};
2use client::UserStore;
3use gpui::{
4 actions, elements::*, ClipboardItem, CursorStyle, Entity, ModelHandle, MouseButton,
5 MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
6};
7use project::Project;
8use settings::Settings;
9
10actions!(contacts_popover, [ToggleContactFinder]);
11
12pub fn init(cx: &mut MutableAppContext) {
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, |_, cx| {
102 Flex::column()
103 .with_child(child.flex(1., true).boxed())
104 .with_children(
105 self.user_store
106 .read(cx)
107 .invite_info()
108 .cloned()
109 .and_then(|info| {
110 enum InviteLink {}
111
112 if info.count > 0 {
113 Some(
114 MouseEventHandler::<InviteLink>::new(0, cx, |state, cx| {
115 let style = theme
116 .contacts_popover
117 .invite_row
118 .style_for(state, false)
119 .clone();
120
121 let copied =
122 cx.read_from_clipboard().map_or(false, |item| {
123 item.text().as_str() == info.url.as_ref()
124 });
125
126 Label::new(
127 format!(
128 "{} invite link ({} left)",
129 if copied { "Copied" } else { "Copy" },
130 info.count
131 ),
132 style.label.clone(),
133 )
134 .aligned()
135 .left()
136 .constrained()
137 .with_height(theme.contacts_popover.invite_row_height)
138 .contained()
139 .with_style(style.container)
140 .boxed()
141 })
142 .with_cursor_style(CursorStyle::PointingHand)
143 .on_click(MouseButton::Left, move |_, cx| {
144 cx.write_to_clipboard(ClipboardItem::new(
145 info.url.to_string(),
146 ));
147 cx.notify();
148 })
149 .boxed(),
150 )
151 } else {
152 None
153 }
154 }),
155 )
156 .contained()
157 .with_style(theme.contacts_popover.container)
158 .constrained()
159 .with_width(theme.contacts_popover.width)
160 .with_height(theme.contacts_popover.height)
161 .boxed()
162 })
163 .on_down_out(MouseButton::Left, move |_, cx| {
164 cx.dispatch_action(ToggleContactsMenu);
165 })
166 .boxed()
167 }
168
169 fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext<Self>) {
170 if cx.is_self_focused() {
171 match &self.child {
172 Child::ContactList(child) => cx.focus(child),
173 Child::ContactFinder(child) => cx.focus(child),
174 }
175 }
176 }
177}