1use call::{room, ActiveCall};
2use client::User;
3use gpui::{
4 actions,
5 elements::*,
6 geometry::{rect::RectF, vector::vec2f},
7 Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext, WindowBounds,
8 WindowKind, WindowOptions,
9};
10use project::Project;
11use settings::Settings;
12use std::sync::Arc;
13use workspace::{AppState, Workspace};
14
15actions!(project_shared_notification, [JoinProject, DismissProject]);
16
17pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
18 cx.add_action(ProjectSharedNotification::join);
19 cx.add_action(ProjectSharedNotification::dismiss);
20
21 let active_call = ActiveCall::global(cx);
22 cx.subscribe(&active_call, move |_, event, cx| match event {
23 room::Event::RemoteProjectShared { owner, project_id } => {
24 cx.add_window(
25 WindowOptions {
26 bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(300., 400.))),
27 titlebar: None,
28 center: true,
29 kind: WindowKind::PopUp,
30 is_movable: false,
31 },
32 |_| ProjectSharedNotification::new(*project_id, owner.clone(), app_state.clone()),
33 );
34 }
35 })
36 .detach();
37}
38
39pub struct ProjectSharedNotification {
40 project_id: u64,
41 owner: Arc<User>,
42 app_state: Arc<AppState>,
43}
44
45impl ProjectSharedNotification {
46 fn new(project_id: u64, owner: Arc<User>, app_state: Arc<AppState>) -> Self {
47 Self {
48 project_id,
49 owner,
50 app_state,
51 }
52 }
53
54 fn join(&mut self, _: &JoinProject, cx: &mut ViewContext<Self>) {
55 let project_id = self.project_id;
56 let app_state = self.app_state.clone();
57 cx.spawn_weak(|_, mut cx| async move {
58 let project = Project::remote(
59 project_id,
60 app_state.client.clone(),
61 app_state.user_store.clone(),
62 app_state.project_store.clone(),
63 app_state.languages.clone(),
64 app_state.fs.clone(),
65 cx.clone(),
66 )
67 .await?;
68
69 cx.add_window((app_state.build_window_options)(), |cx| {
70 let mut workspace = Workspace::new(project, app_state.default_item_factory, cx);
71 (app_state.initialize_workspace)(&mut workspace, &app_state, cx);
72 workspace
73 });
74
75 anyhow::Ok(())
76 })
77 .detach_and_log_err(cx);
78
79 let window_id = cx.window_id();
80 cx.remove_window(window_id);
81 }
82
83 fn dismiss(&mut self, _: &DismissProject, cx: &mut ViewContext<Self>) {
84 let window_id = cx.window_id();
85 cx.remove_window(window_id);
86 }
87
88 fn render_owner(&self, cx: &mut RenderContext<Self>) -> ElementBox {
89 let theme = &cx.global::<Settings>().theme.project_shared_notification;
90 Flex::row()
91 .with_children(
92 self.owner
93 .avatar
94 .clone()
95 .map(|avatar| Image::new(avatar).with_style(theme.owner_avatar).boxed()),
96 )
97 .with_child(
98 Label::new(
99 format!("{} has shared a new project", self.owner.github_login),
100 theme.message.text.clone(),
101 )
102 .boxed(),
103 )
104 .boxed()
105 }
106
107 fn render_buttons(&self, cx: &mut RenderContext<Self>) -> ElementBox {
108 enum Join {}
109 enum Dismiss {}
110
111 Flex::row()
112 .with_child(
113 MouseEventHandler::<Join>::new(0, cx, |_, cx| {
114 let theme = &cx.global::<Settings>().theme.project_shared_notification;
115 Label::new("Join".to_string(), theme.join_button.text.clone())
116 .contained()
117 .with_style(theme.join_button.container)
118 .boxed()
119 })
120 .on_click(MouseButton::Left, |_, cx| {
121 cx.dispatch_action(JoinProject);
122 })
123 .boxed(),
124 )
125 .with_child(
126 MouseEventHandler::<Dismiss>::new(0, cx, |_, cx| {
127 let theme = &cx.global::<Settings>().theme.project_shared_notification;
128 Label::new("Dismiss".to_string(), theme.dismiss_button.text.clone())
129 .contained()
130 .with_style(theme.dismiss_button.container)
131 .boxed()
132 })
133 .on_click(MouseButton::Left, |_, cx| {
134 cx.dispatch_action(DismissProject);
135 })
136 .boxed(),
137 )
138 .boxed()
139 }
140}
141
142impl Entity for ProjectSharedNotification {
143 type Event = ();
144}
145
146impl View for ProjectSharedNotification {
147 fn ui_name() -> &'static str {
148 "ProjectSharedNotification"
149 }
150
151 fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
152 Flex::row()
153 .with_child(self.render_owner(cx))
154 .with_child(self.render_buttons(cx))
155 .boxed()
156 }
157}