1use crate::notification_window_options;
2use call::{room, ActiveCall};
3use client::User;
4use collections::HashMap;
5use gpui::{
6 px, AppContext, Div, Element, ParentElement, Render, RenderOnce, Size, Styled, ViewContext,
7 VisualContext,
8};
9use std::sync::{Arc, Weak};
10use ui::{h_stack, v_stack, Avatar, Button, Clickable, Label};
11use workspace::AppState;
12
13pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
14 let app_state = Arc::downgrade(app_state);
15 let active_call = ActiveCall::global(cx);
16 let mut notification_windows = HashMap::default();
17 cx.subscribe(&active_call, move |_, event, cx| match event {
18 room::Event::RemoteProjectShared {
19 owner,
20 project_id,
21 worktree_root_names,
22 } => {
23 let window_size = Size {
24 width: px(380.),
25 height: px(64.),
26 };
27
28 for screen in cx.displays() {
29 let options = notification_window_options(screen, window_size);
30 let window = cx.open_window(options, |cx| {
31 cx.build_view(|_| {
32 ProjectSharedNotification::new(
33 owner.clone(),
34 *project_id,
35 worktree_root_names.clone(),
36 app_state.clone(),
37 )
38 })
39 });
40 notification_windows
41 .entry(*project_id)
42 .or_insert(Vec::new())
43 .push(window);
44 }
45 }
46
47 room::Event::RemoteProjectUnshared { project_id }
48 | room::Event::RemoteProjectJoined { project_id }
49 | room::Event::RemoteProjectInvitationDiscarded { project_id } => {
50 if let Some(windows) = notification_windows.remove(&project_id) {
51 for window in windows {
52 window
53 .update(cx, |_, cx| {
54 // todo!()
55 cx.remove_window();
56 })
57 .ok();
58 }
59 }
60 }
61
62 room::Event::Left => {
63 for (_, windows) in notification_windows.drain() {
64 for window in windows {
65 window
66 .update(cx, |_, cx| {
67 // todo!()
68 cx.remove_window();
69 })
70 .ok();
71 }
72 }
73 }
74 _ => {}
75 })
76 .detach();
77}
78
79pub struct ProjectSharedNotification {
80 project_id: u64,
81 worktree_root_names: Vec<String>,
82 owner: Arc<User>,
83 app_state: Weak<AppState>,
84}
85
86impl ProjectSharedNotification {
87 fn new(
88 owner: Arc<User>,
89 project_id: u64,
90 worktree_root_names: Vec<String>,
91 app_state: Weak<AppState>,
92 ) -> Self {
93 Self {
94 project_id,
95 worktree_root_names,
96 owner,
97 app_state,
98 }
99 }
100
101 fn join(&mut self, cx: &mut ViewContext<Self>) {
102 if let Some(app_state) = self.app_state.upgrade() {
103 workspace::join_remote_project(self.project_id, self.owner.id, app_state, cx)
104 .detach_and_log_err(cx);
105 }
106 }
107
108 fn dismiss(&mut self, cx: &mut ViewContext<Self>) {
109 if let Some(active_room) =
110 ActiveCall::global(cx).read_with(cx, |call, _| call.room().cloned())
111 {
112 active_room.update(cx, |_, cx| {
113 cx.emit(room::Event::RemoteProjectInvitationDiscarded {
114 project_id: self.project_id,
115 });
116 });
117 }
118 }
119
120 fn render_owner(&self) -> impl Element {
121 h_stack()
122 .children(
123 self.owner
124 .avatar
125 .clone()
126 .map(|avatar| Avatar::data(avatar.clone())),
127 )
128 .child(
129 v_stack()
130 .child(Label::new(self.owner.github_login.clone()))
131 .child(Label::new(format!(
132 "is sharing a project in Zed{}",
133 if self.worktree_root_names.is_empty() {
134 ""
135 } else {
136 ":"
137 }
138 )))
139 .children(if self.worktree_root_names.is_empty() {
140 None
141 } else {
142 Some(Label::new(self.worktree_root_names.join(", ")))
143 }),
144 )
145 }
146
147 fn render_buttons(&self, cx: &mut ViewContext<Self>) -> impl Element {
148 let this = cx.view().clone();
149 v_stack()
150 .child(Button::new("open", "Open").render(cx).on_click({
151 let this = this.clone();
152 move |_, cx| {
153 this.update(cx, |this, cx| this.join(cx));
154 }
155 }))
156 .child(
157 Button::new("dismiss", "Dismiss")
158 .render(cx)
159 .on_click(move |_, cx| {
160 this.update(cx, |this, cx| this.dismiss(cx));
161 }),
162 )
163 }
164}
165
166impl Render for ProjectSharedNotification {
167 type Element = Div;
168
169 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
170 h_stack()
171 .size_full()
172 .bg(gpui::red())
173 .child(self.render_owner())
174 .child(self.render_buttons(cx))
175 }
176}