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(cx);
47 this
48 }
49
50 fn toggle_contact_finder(&mut self, _: &ToggleContactFinder, cx: &mut ViewContext<Self>) {
51 match &self.child {
52 Child::ContactList(_) => self.show_contact_finder(cx),
53 Child::ContactFinder(_) => self.show_contact_list(cx),
54 }
55 }
56
57 fn show_contact_finder(&mut self, cx: &mut ViewContext<ContactsPopover>) {
58 let child = cx.add_view(|cx| ContactFinder::new(self.user_store.clone(), cx));
59 cx.focus(&child);
60 self._subscription = Some(cx.subscribe(&child, |_, _, event, cx| match event {
61 crate::contact_finder::Event::Dismissed => cx.emit(Event::Dismissed),
62 }));
63 self.child = Child::ContactFinder(child);
64 cx.notify();
65 }
66
67 fn show_contact_list(&mut self, cx: &mut ViewContext<ContactsPopover>) {
68 let child =
69 cx.add_view(|cx| ContactList::new(self.project.clone(), self.user_store.clone(), cx));
70 cx.focus(&child);
71 self._subscription = Some(cx.subscribe(&child, |_, _, event, cx| match event {
72 crate::contact_list::Event::Dismissed => cx.emit(Event::Dismissed),
73 }));
74 self.child = Child::ContactList(child);
75 cx.notify();
76 }
77}
78
79impl Entity for ContactsPopover {
80 type Event = Event;
81}
82
83impl View for ContactsPopover {
84 fn ui_name() -> &'static str {
85 "ContactsPopover"
86 }
87
88 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
89 let theme = cx.global::<Settings>().theme.clone();
90 let child = match &self.child {
91 Child::ContactList(child) => ChildView::new(child, cx),
92 Child::ContactFinder(child) => ChildView::new(child, cx),
93 };
94
95 MouseEventHandler::<ContactsPopover>::new(0, cx, |_, cx| {
96 Flex::column()
97 .with_child(child.flex(1., true).boxed())
98 .with_children(
99 self.user_store
100 .read(cx)
101 .invite_info()
102 .cloned()
103 .and_then(|info| {
104 enum InviteLink {}
105
106 if info.count > 0 {
107 Some(
108 MouseEventHandler::<InviteLink>::new(0, cx, |state, cx| {
109 let style = theme
110 .contacts_popover
111 .invite_row
112 .style_for(state, false)
113 .clone();
114
115 let copied =
116 cx.read_from_clipboard().map_or(false, |item| {
117 item.text().as_str() == info.url.as_ref()
118 });
119
120 Label::new(
121 format!(
122 "{} invite link ({} left)",
123 if copied { "Copied" } else { "Copy" },
124 info.count
125 ),
126 style.label.clone(),
127 )
128 .aligned()
129 .left()
130 .constrained()
131 .with_height(theme.contacts_popover.invite_row_height)
132 .contained()
133 .with_style(style.container)
134 .boxed()
135 })
136 .with_cursor_style(CursorStyle::PointingHand)
137 .on_click(MouseButton::Left, move |_, cx| {
138 cx.write_to_clipboard(ClipboardItem::new(
139 info.url.to_string(),
140 ));
141 cx.notify();
142 })
143 .boxed(),
144 )
145 } else {
146 None
147 }
148 }),
149 )
150 .contained()
151 .with_style(theme.contacts_popover.container)
152 .constrained()
153 .with_width(theme.contacts_popover.width)
154 .with_height(theme.contacts_popover.height)
155 .boxed()
156 })
157 .on_down_out(MouseButton::Left, move |_, cx| {
158 cx.dispatch_action(ToggleContactsMenu);
159 })
160 .boxed()
161 }
162
163 fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext<Self>) {
164 if cx.is_self_focused() {
165 match &self.child {
166 Child::ContactList(child) => cx.focus(child),
167 Child::ContactFinder(child) => cx.focus(child),
168 }
169 }
170 }
171}