1use call::{room, ActiveCall};
2use client::User;
3use gpui::{
4 actions,
5 elements::*,
6 geometry::{rect::RectF, vector::vec2f},
7 CursorStyle, Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext,
8 WindowBounds, WindowKind, WindowOptions,
9};
10use settings::Settings;
11use std::sync::Arc;
12use workspace::JoinProject;
13
14actions!(project_shared_notification, [DismissProject]);
15
16pub fn init(cx: &mut MutableAppContext) {
17 cx.add_action(ProjectSharedNotification::join);
18 cx.add_action(ProjectSharedNotification::dismiss);
19
20 let active_call = ActiveCall::global(cx);
21 cx.subscribe(&active_call, move |_, event, cx| match event {
22 room::Event::RemoteProjectShared { owner, project_id } => {
23 const PADDING: f32 = 16.;
24 let screen_size = cx.platform().screen_size();
25 let window_size = vec2f(366., 64.);
26 cx.add_window(
27 WindowOptions {
28 bounds: WindowBounds::Fixed(RectF::new(
29 vec2f(screen_size.x() - window_size.x() - PADDING, PADDING),
30 window_size,
31 )),
32 titlebar: None,
33 center: false,
34 kind: WindowKind::PopUp,
35 is_movable: false,
36 },
37 |_| ProjectSharedNotification::new(*project_id, owner.clone()),
38 );
39 }
40 })
41 .detach();
42}
43
44pub struct ProjectSharedNotification {
45 project_id: u64,
46 owner: Arc<User>,
47}
48
49impl ProjectSharedNotification {
50 fn new(project_id: u64, owner: Arc<User>) -> Self {
51 Self { project_id, owner }
52 }
53
54 fn join(&mut self, _: &JoinProject, cx: &mut ViewContext<Self>) {
55 let window_id = cx.window_id();
56 cx.remove_window(window_id);
57 cx.propagate_action();
58 }
59
60 fn dismiss(&mut self, _: &DismissProject, cx: &mut ViewContext<Self>) {
61 let window_id = cx.window_id();
62 cx.remove_window(window_id);
63 }
64
65 fn render_owner(&self, cx: &mut RenderContext<Self>) -> ElementBox {
66 let theme = &cx.global::<Settings>().theme.project_shared_notification;
67 Flex::row()
68 .with_children(self.owner.avatar.clone().map(|avatar| {
69 Image::new(avatar)
70 .with_style(theme.owner_avatar)
71 .aligned()
72 .boxed()
73 }))
74 .with_child(
75 Flex::column()
76 .with_child(
77 Label::new(
78 self.owner.github_login.clone(),
79 theme.owner_username.text.clone(),
80 )
81 .contained()
82 .with_style(theme.owner_username.container)
83 .boxed(),
84 )
85 .with_child(
86 Label::new(
87 "has shared a project with you".into(),
88 theme.message.text.clone(),
89 )
90 .contained()
91 .with_style(theme.message.container)
92 .boxed(),
93 )
94 .contained()
95 .with_style(theme.owner_metadata)
96 .aligned()
97 .boxed(),
98 )
99 .contained()
100 .with_style(theme.owner_container)
101 .flex(1., true)
102 .boxed()
103 }
104
105 fn render_buttons(&self, cx: &mut RenderContext<Self>) -> ElementBox {
106 enum Join {}
107 enum Dismiss {}
108
109 let project_id = self.project_id;
110 let owner_user_id = self.owner.id;
111
112 Flex::column()
113 .with_child(
114 MouseEventHandler::<Join>::new(0, cx, |_, cx| {
115 let theme = &cx.global::<Settings>().theme.project_shared_notification;
116 Label::new("Join".to_string(), theme.join_button.text.clone())
117 .aligned()
118 .contained()
119 .with_style(theme.join_button.container)
120 .boxed()
121 })
122 .with_cursor_style(CursorStyle::PointingHand)
123 .on_click(MouseButton::Left, move |_, cx| {
124 cx.dispatch_action(JoinProject {
125 project_id,
126 follow_user_id: owner_user_id,
127 });
128 })
129 .flex(1., true)
130 .boxed(),
131 )
132 .with_child(
133 MouseEventHandler::<Dismiss>::new(0, cx, |_, cx| {
134 let theme = &cx.global::<Settings>().theme.project_shared_notification;
135 Label::new("Dismiss".to_string(), theme.dismiss_button.text.clone())
136 .aligned()
137 .contained()
138 .with_style(theme.dismiss_button.container)
139 .boxed()
140 })
141 .with_cursor_style(CursorStyle::PointingHand)
142 .on_click(MouseButton::Left, |_, cx| {
143 cx.dispatch_action(DismissProject);
144 })
145 .flex(1., true)
146 .boxed(),
147 )
148 .constrained()
149 .with_width(
150 cx.global::<Settings>()
151 .theme
152 .project_shared_notification
153 .button_width,
154 )
155 .boxed()
156 }
157}
158
159impl Entity for ProjectSharedNotification {
160 type Event = ();
161}
162
163impl View for ProjectSharedNotification {
164 fn ui_name() -> &'static str {
165 "ProjectSharedNotification"
166 }
167
168 fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
169 let background = cx
170 .global::<Settings>()
171 .theme
172 .project_shared_notification
173 .background;
174 Flex::row()
175 .with_child(self.render_owner(cx))
176 .with_child(self.render_buttons(cx))
177 .contained()
178 .with_background_color(background)
179 .expanded()
180 .boxed()
181 }
182}